am 4c111300: bouncycastle 1.47 upgrade

* commit '4c111300c39cb2e27f07fc2ae3b00e23ed4443b2':
  bouncycastle 1.47 upgrade
diff --git a/NOTICE b/NOTICE
index d2e4437..95c0068 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,4 +1,4 @@
-Copyright (c) 2000-2010 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
+Copyright (c) 2000-2011 The Legion Of The Bouncy Castle (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/README.android b/README.android
index fe40d40..7da2e79 100644
--- a/README.android
+++ b/README.android
@@ -45,7 +45,91 @@
 
 7) Run tests to make sure things are working:
 
-     See external/openssl/README.android for test instructions
+     Some suggested tests by area:
+     - java.security.Provider
+       libcore/luni/src/test/java/libcore/java/security/ProviderTest.java
+       libcore/luni/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java
+     - java.security.AlgorithmParameterGenerator
+       libcore/luni/src/test/java/libcore/java/security/OldAlgorithmParameterGeneratorTest.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParameterGeneratorTestDH.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParameterGeneratorTestDSA.java
+     - java.security.AlgorithmParameters
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParametersTestDSA.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParametersTestAES.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParametersTestDH.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParametersTestDESede.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParametersTestDES.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/AlgorithmParametersTestOAEP.java
+       libcore/luni/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParametersTest.java
+     - java.security.cert.CertPathBuilder
+       libcore/luni/src/test/java/tests/targets/security/cert/CertPathBuilderTestPKIX.java
+     - java.security.cert.CertPathValidator
+       libcore/luni/src/test/java/tests/targets/security/cert/CertPathValidatorTestPKIX.java
+     - java.security.cert.CertStore
+       libcore/luni/src/test/java/tests/security/cert/CertStoreSpiTest.java
+       libcore/luni/src/test/java/tests/security/cert/CertStore2Test.java
+       libcore/luni/src/test/java/tests/security/cert/CertStore1Test.java
+       libcore/luni/src/test/java/tests/security/cert/CertStoreExceptionTest.java
+     - java.security.cert.CertificateFactory
+       libcore/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
+       libcore/luni/src/test/java/tests/targets/security/cert/CertificateFactoryTestX509.java
+     - javax.crypto.Cipher
+       libcore/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+       libcore/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
+       libcore/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/NullCipherTest.java
+     - javax.crypto.KeyAgreement
+       libcore/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/KeyAgreementTest.java
+     - java.security.KeyFactory
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/KeyFactoryTestDH.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/KeyFactoryTestDSA.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/KeyFactoryTestRSA.java
+       libcore/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyFactoryTest.java
+     - javax.crypto.KeyGenerator
+       libcore/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
+       libcore/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/KeyGeneratorTest.java
+     - javax.net.ssl.KeyManagerFactory
+       libcore/luni/src/test/java/libcore/javax/net/ssl/KeyManagerFactoryTest.java
+     - java.security.KeyPairGenerator
+       libcore/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
+       libcore/luni/src/test/java/libcore/java/security/OldKeyPairGeneratorTestDH.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/KeyPairGeneratorTestRSA.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/KeyPairGeneratorTestDSA.java
+       libcore/luni/src/test/java/libcore/javax/crypto/spec/KeyPairGeneratorTestDH.java
+       libcore/luni/src/test/java/tests/security/interfaces/DSAKeyPairGeneratorTest.java
+     - java.security.KeyStore
+       libcore/luni/src/test/java/libcore/java/security/KeyStoreTest.java
+       libcore/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreTest.java
+       libcore/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java
+     - javax.crypto.Mac
+       libcore/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
+     - java.security.MessageDigest
+       libcore/luni/src/test/java/libcore/java/security/MessageDigestTest.java
+       libcore/luni/src/test/java/tests/targets/security/MessageDigestTestMD2.java
+       libcore/luni/src/test/java/tests/targets/security/MessageDigestTestMD5.java
+       libcore/luni/src/test/java/tests/targets/security/MessageDigestTestSHA256.java
+       libcore/luni/src/test/java/tests/targets/security/MessageDigestTestSHA1.java
+       libcore/luni/src/test/java/tests/targets/security/MessageDigestTestSHA512.java
+       libcore/luni/src/test/java/tests/targets/security/MessageDigestTestSHA384.java
+     - javax.net.ssl.SSLContext
+       libcore/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
+     - javax.crypto.SecretKeyFactory
+       libcore/luni/src/test/java/libcore/javax/crypto/SecretKeyFactoryTest.java
+       libcore/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SecretKeyFactoryTest.java
+     - java.security.SecureRandom
+       libcore/luni/src/test/java/libcore/java/security/SecureRandomTest.java
+       libcore/luni/src/test/java/tests/java/security/SecureRandomTest.java
+       libcore/luni/src/test/java/tests/targets/security/SecureRandomTestSHA1PRNG.java
+     - java.security.Signature
+       libcore/luni/src/test/java/libcore/java/security/SignatureTest.java
+       libcore/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureTest.java
+       libcore/luni/src/test/java/org/apache/harmony/security/tests/java/security/SignatureTest.java
+       libcore/luni/src/test/java/tests/targets/security/SignatureTestMD2withRSA.java
+     - javax.net.ssl.TrustManagerFactory
+       libcore/luni/src/test/java/libcore/javax/net/ssl/TrustManagerFactoryTest.java
+     - javax.net.ssl.SSLSocket and javax.net.ssl.SSLEngine (which touch on Cipher, MessageDigest, Signature)
+       libcore/luni/src/test/java/libcore/javax/net/ssl/
+     - Test Android additions to bouncycastle such as org.bouncycastle.crypto.digests.OpenSSLDigest and org.bouncycastle.jce.provider.CertBlacklist
+       libcore/luni/src/test/java/com/android/org/bouncycastle/
 
 8) Do a full build before checking in:
 
diff --git a/bouncycastle.config b/bouncycastle.config
index 4132420..aa3c96d 100644
--- a/bouncycastle.config
+++ b/bouncycastle.config
@@ -14,43 +14,31 @@
 org/bouncycastle/asn1/ntt \
 org/bouncycastle/asn1/ocsp \
 org/bouncycastle/asn1/smime \
-org/bouncycastle/asn1/test \
 org/bouncycastle/asn1/tsp \
 org/bouncycastle/asn1/x509/qualified \
 org/bouncycastle/asn1/x509/sigi \
-org/bouncycastle/bcpg \
-org/bouncycastle/cert \
-org/bouncycastle/cms \
 org/bouncycastle/crypto/agreement/kdf \
 org/bouncycastle/crypto/agreement/srp \
 org/bouncycastle/crypto/examples \
 org/bouncycastle/crypto/prng \
-org/bouncycastle/crypto/test \
 org/bouncycastle/crypto/tls/ \
 org/bouncycastle/i18n/ \
+org/bouncycastle/jcajce/provider/asymmetric/ecgost \
+org/bouncycastle/jcajce/provider/asymmetric/elgamal \
+org/bouncycastle/jcajce/provider/asymmetric/gost \
 org/bouncycastle/jce/examples \
 org/bouncycastle/jce/provider/test \
-org/bouncycastle/mail \
-org/bouncycastle/mozilla \
+org/bouncycastle/math/ntru \
 org/bouncycastle/ocsp \
-org/bouncycastle/openpgp \
-org/bouncycastle/openssl/test \
-org/bouncycastle/operator \
-org/bouncycastle/pkcs \
-org/bouncycastle/tsp \
-org/bouncycastle/util/encoders/test \
 org/bouncycastle/util/test \
-org/bouncycastle/voms \
 org/bouncycastle/x509/examples \
 "
 
 # files
 UNNEEDED_SOURCES+=" \
 org/bouncycastle/LICENSE.java \
-org/bouncycastle/asn1/ASN1Boolean.java \
 org/bouncycastle/asn1/ASN1Generator.java \
 org/bouncycastle/asn1/BERGenerator.java \
-org/bouncycastle/asn1/BERNull.java \
 org/bouncycastle/asn1/BEROctetStringGenerator.java \
 org/bouncycastle/asn1/BERSequenceGenerator.java \
 org/bouncycastle/asn1/DERGenerator.java \
@@ -155,7 +143,7 @@
 org/bouncycastle/asn1/x509/UserNotice.java \
 org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java \
 org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java \
-org/bouncycastle/asn1/x509/X509Attributes.java \
+org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java \
 org/bouncycastle/asn1/x509/package.html \
 org/bouncycastle/asn1/x9/KeySpecificInfo.java \
 org/bouncycastle/asn1/x9/OtherInfo.java \
@@ -178,6 +166,7 @@
 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 \
@@ -194,6 +183,8 @@
 org/bouncycastle/crypto/engines/IDEAEngine.java \
 org/bouncycastle/crypto/engines/IESEngine.java \
 org/bouncycastle/crypto/engines/ISAACEngine.java \
+org/bouncycastle/crypto/engines/IndexGenerator.java \
+org/bouncycastle/crypto/engines/NTRUEngine.java \
 org/bouncycastle/crypto/engines/NaccacheSternEngine.java \
 org/bouncycastle/crypto/engines/NoekeonEngine.java \
 org/bouncycastle/crypto/engines/NullEngine.java \
@@ -224,8 +215,11 @@
 org/bouncycastle/crypto/generators/KDF1BytesGenerator.java \
 org/bouncycastle/crypto/generators/KDF2BytesGenerator.java \
 org/bouncycastle/crypto/generators/MGF1BytesGenerator.java \
+org/bouncycastle/crypto/generators/NTRUEncryptionKeyPairGenerator.java \
+org/bouncycastle/crypto/generators/NTRUSigningKeyPairGenerator.java \
 org/bouncycastle/crypto/generators/NaccacheSternKeyPairGenerator.java \
 org/bouncycastle/crypto/generators/RSABlindingFactorGenerator.java \
+org/bouncycastle/crypto/generators/SCrypt.java \
 org/bouncycastle/crypto/generators/package.html \
 org/bouncycastle/crypto/io/SignerInputStream.java \
 org/bouncycastle/crypto/io/SignerOutputStream.java \
@@ -239,6 +233,7 @@
 org/bouncycastle/crypto/macs/VMPCMac.java \
 org/bouncycastle/crypto/macs/package.html \
 org/bouncycastle/crypto/modes/EAXBlockCipher.java \
+org/bouncycastle/crypto/modes/GOFBBlockCipher.java \
 org/bouncycastle/crypto/modes/OpenPGPCFBBlockCipher.java \
 org/bouncycastle/crypto/modes/PGPCFBBlockCipher.java \
 org/bouncycastle/crypto/modes/PaddedBlockCipher.java \
@@ -269,6 +264,16 @@
 org/bouncycastle/crypto/params/MGFParameters.java \
 org/bouncycastle/crypto/params/MQVPrivateParameters.java \
 org/bouncycastle/crypto/params/MQVPublicParameters.java \
+org/bouncycastle/crypto/params/NTRUEncryptionKeyGenerationParameters.java \
+org/bouncycastle/crypto/params/NTRUEncryptionKeyParameters.java \
+org/bouncycastle/crypto/params/NTRUEncryptionParameters.java \
+org/bouncycastle/crypto/params/NTRUEncryptionPrivateKeyParameters.java \
+org/bouncycastle/crypto/params/NTRUEncryptionPublicKeyParameters.java \
+org/bouncycastle/crypto/params/NTRUParameters.java \
+org/bouncycastle/crypto/params/NTRUSigningKeyGenerationParameters.java \
+org/bouncycastle/crypto/params/NTRUSigningParameters.java \
+org/bouncycastle/crypto/params/NTRUSigningPrivateKeyParameters.java \
+org/bouncycastle/crypto/params/NTRUSigningPublicKeyParameters.java \
 org/bouncycastle/crypto/params/NaccacheSternKeyGenerationParameters.java \
 org/bouncycastle/crypto/params/NaccacheSternKeyParameters.java \
 org/bouncycastle/crypto/params/NaccacheSternPrivateKeyParameters.java \
@@ -284,9 +289,49 @@
 org/bouncycastle/crypto/signers/GenericSigner.java \
 org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java \
 org/bouncycastle/crypto/signers/ISO9796d2Signer.java \
+org/bouncycastle/crypto/signers/NTRUSigner.java \
+org/bouncycastle/crypto/signers/NTRUSignerPrng.java \
 org/bouncycastle/crypto/signers/PSSSigner.java \
 org/bouncycastle/crypto/signers/package.html \
 org/bouncycastle/crypto/util/package.html \
+org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java \
+org/bouncycastle/jcajce/provider/asymmetric/ElGamal.java \
+org/bouncycastle/jcajce/provider/asymmetric/GOST.java \
+org/bouncycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java \
+org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java \
+org/bouncycastle/jcajce/provider/digest/GOST3411.java \
+org/bouncycastle/jcajce/provider/digest/MD2.java \
+org/bouncycastle/jcajce/provider/digest/MD4.java \
+org/bouncycastle/jcajce/provider/digest/RIPEMD128.java \
+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/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/GOST28147.java \
+org/bouncycastle/jcajce/provider/symmetric/Grain128.java \
+org/bouncycastle/jcajce/provider/symmetric/Grainv1.java \
+org/bouncycastle/jcajce/provider/symmetric/HC128.java \
+org/bouncycastle/jcajce/provider/symmetric/HC256.java \
+org/bouncycastle/jcajce/provider/symmetric/IDEA.java \
+org/bouncycastle/jcajce/provider/symmetric/Noekeon.java \
+org/bouncycastle/jcajce/provider/symmetric/RC2.java \
+org/bouncycastle/jcajce/provider/symmetric/RC5.java \
+org/bouncycastle/jcajce/provider/symmetric/RC6.java \
+org/bouncycastle/jcajce/provider/symmetric/Rijndael.java \
+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/Skipjack.java \
+org/bouncycastle/jcajce/provider/symmetric/TEA.java \
+org/bouncycastle/jcajce/provider/symmetric/Twofish.java \
+org/bouncycastle/jcajce/provider/symmetric/VMPC.java \
+org/bouncycastle/jcajce/provider/symmetric/VMPCKSA3.java \
+org/bouncycastle/jcajce/provider/symmetric/XTEA.java \
 org/bouncycastle/jce/ECGOST3410NamedCurveTable.java \
 org/bouncycastle/jce/ECKeyUtil.java \
 org/bouncycastle/jce/ECPointUtil.java \
@@ -313,16 +358,9 @@
 org/bouncycastle/jce/provider/BrokenPBE.java \
 org/bouncycastle/jce/provider/ElGamalUtil.java \
 org/bouncycastle/jce/provider/GOST3410Util.java \
-org/bouncycastle/jce/provider/JCEElGamalCipher.java \
 org/bouncycastle/jce/provider/JCEElGamalPrivateKey.java \
 org/bouncycastle/jce/provider/JCEElGamalPublicKey.java \
 org/bouncycastle/jce/provider/JCEIESCipher.java \
-org/bouncycastle/jce/provider/JDKECDSAAlgParameters.java \
-org/bouncycastle/jce/provider/JDKGOST3410PrivateKey.java \
-org/bouncycastle/jce/provider/JDKGOST3410PublicKey.java \
-org/bouncycastle/jce/provider/JDKGOST3410Signer.java \
-org/bouncycastle/jce/provider/JDKISOSignature.java \
-org/bouncycastle/jce/provider/JDKPSSSigner.java \
 org/bouncycastle/jce/provider/MultiCertStoreSpi.java \
 org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java \
 org/bouncycastle/jce/provider/PKIXAttrCertPathValidatorSpi.java \
@@ -340,27 +378,6 @@
 org/bouncycastle/jce/provider/X509StoreLDAPCRLs.java \
 org/bouncycastle/jce/provider/X509StoreLDAPCertPairs.java \
 org/bouncycastle/jce/provider/X509StoreLDAPCerts.java \
-org/bouncycastle/jce/provider/symmetric/CAST5.java \
-org/bouncycastle/jce/provider/symmetric/CAST6.java \
-org/bouncycastle/jce/provider/symmetric/Camellia.java \
-org/bouncycastle/jce/provider/symmetric/Grain128.java \
-org/bouncycastle/jce/provider/symmetric/Grainv1.java \
-org/bouncycastle/jce/provider/symmetric/HC128.java \
-org/bouncycastle/jce/provider/symmetric/HC256.java \
-org/bouncycastle/jce/provider/symmetric/IDEA.java \
-org/bouncycastle/jce/provider/symmetric/Noekeon.java \
-org/bouncycastle/jce/provider/symmetric/RC5.java \
-org/bouncycastle/jce/provider/symmetric/RC6.java \
-org/bouncycastle/jce/provider/symmetric/Rijndael.java \
-org/bouncycastle/jce/provider/symmetric/SEED.java \
-org/bouncycastle/jce/provider/symmetric/Salsa20.java \
-org/bouncycastle/jce/provider/symmetric/Serpent.java \
-org/bouncycastle/jce/provider/symmetric/Skipjack.java \
-org/bouncycastle/jce/provider/symmetric/TEA.java \
-org/bouncycastle/jce/provider/symmetric/Twofish.java \
-org/bouncycastle/jce/provider/symmetric/VMPC.java \
-org/bouncycastle/jce/provider/symmetric/VMPCKSA3.java \
-org/bouncycastle/jce/provider/symmetric/XTEA.java \
 org/bouncycastle/jce/spec/ElGamalGenParameterSpec.java \
 org/bouncycastle/jce/spec/ElGamalKeySpec.java \
 org/bouncycastle/jce/spec/ElGamalParameterSpec.java \
@@ -378,12 +395,7 @@
 org/bouncycastle/jce/spec/package.html \
 org/bouncycastle/math/ec/ReferenceMultiplier.java \
 org/bouncycastle/math/ec/package.html \
-org/bouncycastle/math/ec/test \
-org/bouncycastle/openssl/PKCS8Generator.java \
-org/bouncycastle/openssl/package.html \
-org/bouncycastle/util/AllTests.java \
 org/bouncycastle/util/CollectionStore.java \
-org/bouncycastle/util/IPTest.java \
 org/bouncycastle/util/StreamParser.java \
 org/bouncycastle/util/StreamParsingException.java \
 org/bouncycastle/util/encoders/BufferedDecoder.java \
@@ -394,8 +406,6 @@
 org/bouncycastle/util/encoders/UrlBase64Encoder.java \
 org/bouncycastle/util/encoders/package.html \
 org/bouncycastle/util/io/TeeInputStream.java \
-org/bouncycastle/util/io/TeeOutputStream.java \
-org/bouncycastle/util/io/pem/AllTests.java \
 org/bouncycastle/x509/CertPathReviewerException.java \
 org/bouncycastle/x509/CertPathReviewerMessages_de.properties \
 org/bouncycastle/x509/NoSuchParserException.java \
diff --git a/bouncycastle.version b/bouncycastle.version
index 281f7f5..a9eb1be 100644
--- a/bouncycastle.version
+++ b/bouncycastle.version
@@ -1,2 +1,2 @@
-BOUNCYCASTLE_JDK=16
-BOUNCYCASTLE_VERSION=146
+BOUNCYCASTLE_JDK=15on
+BOUNCYCASTLE_VERSION=147
diff --git a/patches/README b/patches/README
index c0f5697..fa4c751 100644
--- a/patches/README
+++ b/patches/README
@@ -16,7 +16,6 @@
 - singleton DERNull (BouncyCastle now does this but we make constructor private to be sure)
 - similarly made DERBoolean constructor private and moved to DERBoolean.{getInstance,TRUE,FALSE}
 - removed use of Boolean constructor
-- DERPrintableString interns its internal String values
 - DERObjectIdentifier interns its internal String indentifer value
 - changed uses of 'new Integer' to 'Integer.valueOf'
 - X509CertificateObject.getEncoded caches its result
@@ -29,7 +28,6 @@
 - Fixed cut & paste instanceof error in EncryptedPrivateKeyInfo
 - Make BouncyCastleProvider.PROVIDER_NAME final
 - Added wrapper for SecretKeyFactory.PBKDF2WithHmacSHA1
-- Added DSA support to JDKKeyManager.engineGetKeySpec
 - Fixed CertBlacklist to do a by-value comparison of public keys
 
 Other security changes:
diff --git a/patches/android.patch b/patches/android.patch
index 40a24f8..33df91a 100644
--- a/patches/android.patch
+++ b/patches/android.patch
@@ -1,23 +1,9 @@
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1InputStream.java bcprov-jdk16-146/org/bouncycastle/asn1/ASN1InputStream.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1InputStream.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/ASN1InputStream.java	2012-07-27 18:48:00.011478563 +0000
-@@ -363,7 +363,9 @@
-             case BMP_STRING:
-                 return new DERBMPString(bytes);
-             case BOOLEAN:
--                return new ASN1Boolean(bytes);
-+                // BEGIN android-changed
-+                return DERBoolean.getInstance(bytes);
-+                // END android-changed
-             case ENUMERATED:
-                 return new ASN1Enumerated(bytes);
-             case GENERALIZED_TIME:
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk16-146/org/bouncycastle/asn1/ASN1Null.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1Null.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/ASN1Null.java	2012-07-27 18:47:59.981477999 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk15on-147/org/bouncycastle/asn1/ASN1Null.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/ASN1Null.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/ASN1Null.java	2012-09-11 00:12:44.000000000 +0000
 @@ -8,9 +8,11 @@
  public abstract class ASN1Null
-     extends ASN1Object
+     extends ASN1Primitive
  {
 -    public ASN1Null()
 +    // BEGIN android-changed
@@ -26,23 +12,23 @@
      }
 +    // END android-changed
  
-     public int hashCode()
+     public static ASN1Null getInstance(Object o)
      {
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk16-146/org/bouncycastle/asn1/DERBoolean.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERBoolean.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/DERBoolean.java	2012-07-27 18:47:59.981477999 +0000
-@@ -5,7 +5,9 @@
- public class DERBoolean
-     extends ASN1Object
- {
--    byte         value;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk15on-147/org/bouncycastle/asn1/DERBoolean.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERBoolean.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/DERBoolean.java	2012-09-11 00:12:44.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 };
+ 
+-    private byte[]         value;
 +    // BEGIN android-changed
-+    private final byte  value;
++    final private byte[]         value;
 +    // END android-changed
  
-     public static final DERBoolean FALSE = new DERBoolean(false);
-     public static final DERBoolean TRUE  = new DERBoolean(true);
-@@ -35,6 +37,17 @@
+     public static final ASN1Boolean FALSE = new ASN1Boolean(false);
+     public static final ASN1Boolean TRUE  = new ASN1Boolean(true);
+@@ -46,6 +48,17 @@
          return (value ? TRUE : FALSE);
      }
  
@@ -55,44 +41,25 @@
 +    {
 +        return (octets[0] != 0) ? TRUE : FALSE;
 +    }
-+    // END android-added
 +
++    // END android-added
      /**
       * return a Boolean from a tagged object.
       *
-@@ -56,23 +69,29 @@
-         }
-         else
-         {
--            return new DERBoolean(((ASN1OctetString)o).getOctets());
-+            // BEGIN android-changed
-+            return getInstance(((ASN1OctetString)o).getOctets());
-+            // END android-changed
+@@ -71,7 +84,9 @@
          }
      }
      
--    public DERBoolean(
--        byte[]       value)
--    {
--        if (value.length != 1)
--        {
--            throw new IllegalArgumentException("byte value should have 1 byte in it");
--        }
--        
--        this.value = value[0];
--    }
-+    // BEGIN android-removed
-+    // public DERBoolean(
-+    //     byte[]       value)
-+    // {
-+    //     if (value.length != 1)
-+    //     {
-+    //         throw new IllegalArgumentException("byte value should have 1 byte in it");
-+    //     }
-+    //
-+    //     this.value = value[0];
-+    // }
-+    // END android-removed
+-    DERBoolean(
++    // BEGIN android-changed
++    protected DERBoolean(
++    // END android-changed
+         byte[]       value)
+     {
+         if (value.length != 1)
+@@ -93,8 +108,10 @@
+         }
+     }
  
 -    public DERBoolean(
 +    // BEGIN android-changed
@@ -100,19 +67,14 @@
          boolean     value)
 +    // END android-changed
      {
-         this.value = (value) ? (byte)0xff : (byte)0;
+         this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
      }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk16-146/org/bouncycastle/asn1/DERNull.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERNull.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/DERNull.java	2012-07-27 18:47:59.981477999 +0000
-@@ -10,9 +10,13 @@
- {
-     public static final DERNull INSTANCE = new DERNull();
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk15on-147/org/bouncycastle/asn1/DERNull.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERNull.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/DERNull.java	2012-09-11 00:12:44.000000000 +0000
+@@ -12,7 +12,9 @@
  
--    byte[]  zeroBytes = new byte[0];
-+    // BEGIN android-changed
-+    private static final byte[]  zeroBytes = new byte[0];
-+    // END android-changed
+     private static final byte[]  zeroBytes = new byte[0];
  
 -    public DERNull()
 +    // BEGIN android-changed
@@ -121,10 +83,10 @@
      {
      }
  
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk16-146/org/bouncycastle/asn1/DERObjectIdentifier.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/DERObjectIdentifier.java	2012-07-27 18:48:00.011478563 +0000
-@@ -110,7 +110,13 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk15on-147/org/bouncycastle/asn1/DERObjectIdentifier.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/DERObjectIdentifier.java	2012-09-11 00:12:44.000000000 +0000
+@@ -117,7 +117,13 @@
              }
          }
  
@@ -139,7 +101,7 @@
      }
  
      public DERObjectIdentifier(
-@@ -121,7 +127,13 @@
+@@ -128,7 +134,13 @@
              throw new IllegalArgumentException("string " + identifier + " not an OID");
          }
  
@@ -154,59 +116,37 @@
      }
  
      public String getId()
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk16-146/org/bouncycastle/asn1/DERPrintableString.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERPrintableString.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/DERPrintableString.java	2012-07-27 18:48:00.011478563 +0000
-@@ -9,7 +9,9 @@
-     extends ASN1Object
-     implements DERString
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk15on-147/org/bouncycastle/asn1/DERPrintableString.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/DERPrintableString.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/DERPrintableString.java	2012-09-11 00:12:44.000000000 +0000
+@@ -12,7 +12,9 @@
+     extends ASN1Primitive
+     implements ASN1String
  {
--    String  string;
+-    private byte[]  string;
 +    // BEGIN android-changed
-+    private final String string;
++    private final byte[]  string;
 +    // END android-changed
  
      /**
       * return a printable string from the passed in object.
-@@ -65,7 +67,9 @@
-             cs[i] = (char)(string[i] & 0xff);
-         }
- 
--        this.string = new String(cs);
-+        // BEGIN android-changed
-+        this.string = new String(cs).intern();
-+        // END android-changed
-     }
- 
-     /**
-@@ -94,7 +98,9 @@
-             throw new IllegalArgumentException("string contains illegal characters");
-         }
- 
--        this.string = string;
-+        // BEGIN android-changed
-+        this.string = string.intern();
-+        // END android-changed
-     }
- 
-     public String getString()
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/cms/ContentInfo.java bcprov-jdk16-146/org/bouncycastle/asn1/cms/ContentInfo.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/cms/ContentInfo.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/cms/ContentInfo.java	2012-07-27 18:48:00.011478563 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/cms/ContentInfo.java bcprov-jdk15on-147/org/bouncycastle/asn1/cms/ContentInfo.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/cms/ContentInfo.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/cms/ContentInfo.java	2012-09-11 00:12:44.000000000 +0000
 @@ -12,7 +12,9 @@
  
  public class ContentInfo
-     extends ASN1Encodable
+     extends ASN1Object
 -    implements CMSObjectIdentifiers
 +    // BEGIN android-removed
 +    // implements CMSObjectIdentifiers
 +    // END android-removed
  {
      private ASN1ObjectIdentifier contentType;
-     private DEREncodable        content;
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2012-07-27 18:48:00.011478563 +0000
+     private ASN1Encodable        content;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2012-09-11 00:12:44.000000000 +0000
 @@ -37,10 +37,13 @@
      public static EncryptedPrivateKeyInfo getInstance(
          Object  obj)
@@ -219,12 +159,12 @@
              return (EncryptedPrivateKeyInfo)obj;
          }
 +        // END android-changed
-         else if (obj instanceof ASN1Sequence)
+         else if (obj != null)
          { 
-             return new EncryptedPrivateKeyInfo((ASN1Sequence)obj);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2012-07-27 18:47:59.981477999 +0000
+             return new EncryptedPrivateKeyInfo(ASN1Sequence.getInstance(obj));
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2012-09-11 00:12:44.000000000 +0000
 @@ -10,8 +10,10 @@
      //
      static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
@@ -280,9 +220,9 @@
      static final ASN1ObjectIdentifier    id_hmacWithSHA256       = digestAlgorithm.branch("9");
      static final ASN1ObjectIdentifier    id_hmacWithSHA384       = digestAlgorithm.branch("10");
      static final ASN1ObjectIdentifier    id_hmacWithSHA512       = digestAlgorithm.branch("11");
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2012-07-27 18:47:59.981477999 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2012-09-11 00:12:44.000000000 +0000
 @@ -19,7 +19,9 @@
      private AlgorithmIdentifier maskGenAlgorithm;
      private AlgorithmIdentifier pSourceAlgorithm;
@@ -294,24 +234,24 @@
      public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
      public final static AlgorithmIdentifier DEFAULT_P_SOURCE_ALGORITHM = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]));
      
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2012-07-27 18:47:59.981477999 +0000
-@@ -20,7 +20,9 @@
-     private DERInteger          saltLength;
-     private DERInteger          trailerField;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2012-09-11 00:12:44.000000000 +0000
+@@ -22,7 +22,9 @@
+     private ASN1Integer          saltLength;
+     private ASN1Integer          trailerField;
      
 -    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
 +    // BEGIN android-changed
 +    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
 +    // END android-changed
      public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
-     public final static DERInteger          DEFAULT_SALT_LENGTH = new DERInteger(20);
-     public final static DERInteger          DEFAULT_TRAILER_FIELD = new DERInteger(1);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/util/ASN1Dump.java bcprov-jdk16-146/org/bouncycastle/asn1/util/ASN1Dump.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/util/ASN1Dump.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/util/ASN1Dump.java	2012-07-27 18:48:00.011478563 +0000
-@@ -79,7 +79,9 @@
+     public final static ASN1Integer          DEFAULT_SALT_LENGTH = new ASN1Integer(20);
+     public final static ASN1Integer          DEFAULT_TRAILER_FIELD = new ASN1Integer(1);
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/util/ASN1Dump.java bcprov-jdk15on-147/org/bouncycastle/asn1/util/ASN1Dump.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/util/ASN1Dump.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/util/ASN1Dump.java	2012-09-11 00:12:44.000000000 +0000
+@@ -78,7 +78,9 @@
              {
                  Object  o = e.nextElement();
  
@@ -322,10 +262,10 @@
                  {
                      buf.append(tab);
                      buf.append("NULL");
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/AttCertIssuer.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/AttCertIssuer.java	2012-07-27 18:48:00.011478563 +0000
-@@ -45,7 +45,7 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/AttCertIssuer.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/AttCertIssuer.java	2012-09-11 00:12:44.000000000 +0000
+@@ -46,7 +46,7 @@
          ASN1TaggedObject obj,
          boolean          explicit)
      {
@@ -334,32 +274,57 @@
      }
  
      /**
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/BasicConstraints.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/BasicConstraints.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/BasicConstraints.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/BasicConstraints.java	2012-07-27 18:48:00.011478563 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java	2012-09-11 00:12:44.000000000 +0000
+@@ -14,7 +14,9 @@
+ import org.bouncycastle.asn1.DERSequence;
+ import org.bouncycastle.asn1.DERTaggedObject;
+ import org.bouncycastle.crypto.Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ 
+ /**
+  * The AuthorityKeyIdentifier object.
+@@ -101,7 +103,9 @@
+     public AuthorityKeyIdentifier(
+         SubjectPublicKeyInfo    spki)
+     {
+-        Digest  digest = new SHA1Digest();
++        // BEGIN android-changed
++        Digest  digest = new OpenSSLDigest.SHA1();
++        // END android-changed
+         byte[]  resBuf = new byte[digest.getDigestSize()];
+ 
+         byte[] bytes = spki.getPublicKeyData().getBytes();
+@@ -119,7 +123,9 @@
+         GeneralNames            name,
+         BigInteger              serialNumber)
+     {
+-        Digest  digest = new SHA1Digest();
++        // BEGIN android-changed
++        Digest  digest = new OpenSSLDigest.SHA1();
++        // END android-changed
+         byte[]  resBuf = new byte[digest.getDigestSize()];
+ 
+         byte[] bytes = spki.getPublicKeyData().getBytes();
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/BasicConstraints.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/BasicConstraints.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/BasicConstraints.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/BasicConstraints.java	2012-09-11 00:12:44.000000000 +0000
 @@ -14,7 +14,9 @@
  public class BasicConstraints
-     extends ASN1Encodable
+     extends ASN1Object
  {
 -    DERBoolean  cA = new DERBoolean(false);
 +    // BEGIN android-changed
 +    DERBoolean  cA = DERBoolean.FALSE;
 +    // END android-changed
-     DERInteger  pathLenConstraint = null;
+     ASN1Integer  pathLenConstraint = null;
  
      public static BasicConstraints getInstance(
-@@ -89,7 +91,9 @@
-     {
-         if (cA)
-         {
--            this.cA = new DERBoolean(cA);
-+            // BEGIN android-changed
-+            this.cA = DERBoolean.getInstance(cA);
-+            // END android-changed
-             this.pathLenConstraint = new DERInteger(pathLenConstraint);
-         }
-         else
-@@ -104,7 +108,9 @@
+@@ -81,7 +83,9 @@
      {
          if (cA)
          {
@@ -370,7 +335,7 @@
          }
          else
          {
-@@ -121,7 +127,9 @@
+@@ -98,7 +102,9 @@
      public BasicConstraints(
          int     pathLenConstraint)
      {
@@ -378,12 +343,26 @@
 +        // BEGIN android-changed
 +        this.cA = DERBoolean.TRUE;
 +        // END android-changed
-         this.pathLenConstraint = new DERInteger(pathLenConstraint);
+         this.pathLenConstraint = new ASN1Integer(pathLenConstraint);
      }
  
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2012-07-27 18:48:00.011478563 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/CRLReason.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/CRLReason.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/CRLReason.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/CRLReason.java	2012-09-11 00:12:44.000000000 +0000
+@@ -138,7 +138,9 @@
+ 
+     public static CRLReason lookup(int value)
+     {
+-        Integer idx = new Integer(value);
++        // BEGIN android-changed
++        Integer idx = Integer.valueOf(value);
++        // END android-changed
+ 
+         if (!table.containsKey(idx))
+         {
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2012-09-11 00:12:44.000000000 +0000
 @@ -96,11 +96,15 @@
          }
          if (onlyContainsUserCerts)
@@ -420,10 +399,35 @@
          }
  
          seq = new DERSequence(vec);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Extensions.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Extensions.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Extensions.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Extensions.java	2012-07-27 18:48:00.011478563 +0000
-@@ -400,7 +400,9 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java	2012-09-11 00:12:44.000000000 +0000
+@@ -6,7 +6,9 @@
+ import org.bouncycastle.asn1.ASN1TaggedObject;
+ import org.bouncycastle.asn1.DEROctetString;
+ import org.bouncycastle.crypto.Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ 
+ /**
+  * The SubjectKeyIdentifier object.
+@@ -119,7 +121,9 @@
+ 
+     private static byte[] getDigest(SubjectPublicKeyInfo spki)
+     {
+-        Digest digest = new SHA1Digest();
++        // BEGIN android-changed
++        Digest digest = new OpenSSLDigest.SHA1();
++        // END android-changed
+         byte[]  resBuf = new byte[digest.getDigestSize()];
+ 
+         byte[] bytes = spki.getPublicKeyData().getBytes();
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/X509Extensions.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/X509Extensions.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/X509Extensions.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/X509Extensions.java	2012-09-11 00:12:44.000000000 +0000
+@@ -408,7 +408,9 @@
  
              if (ext.isCritical())
              {
@@ -434,10 +438,10 @@
              }
  
              v.add(ext.getValue());
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Name.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Name.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Name.java	2012-07-27 18:48:00.011478563 +0000
-@@ -249,8 +249,10 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/X509Name.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/X509Name.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/X509Name.java	2012-09-11 00:12:44.000000000 +0000
+@@ -255,8 +255,10 @@
       */
      public static final Hashtable SymbolLookUp = DefaultLookUp;
  
@@ -450,9 +454,9 @@
  
      static
      {
-@@ -432,7 +434,9 @@
-                    {
-                        values.addElement("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
+@@ -445,7 +447,9 @@
+                            throw new IllegalArgumentException("cannot encode value");
+                        }
                     }
 -                   added.addElement((i != 0) ? TRUE : FALSE);  // to allow earlier JDK compatibility
 +                   // BEGIN android-changed
@@ -461,7 +465,7 @@
              }
          }
      }
-@@ -689,7 +693,9 @@
+@@ -702,7 +706,9 @@
  
              if (index == -1)
              {
@@ -472,9 +476,9 @@
              }
  
              String              name = token.substring(0, index);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509NameTokenizer.java
---- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2012-07-27 18:48:00.011478563 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk15on-147/org/bouncycastle/asn1/x509/X509NameTokenizer.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2012-09-11 00:12:44.000000000 +0000
 @@ -58,6 +58,17 @@
                  }
                  else
@@ -493,16 +497,9 @@
                      buf.append(c);
                  }
                  escaped = false;
-@@ -96,4 +107,4 @@
-         index = end;
-         return buf.toString().trim();
-     }
--}
-+}
-\ No newline at end of file
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/PBEParametersGenerator.java bcprov-jdk16-146/org/bouncycastle/crypto/PBEParametersGenerator.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/PBEParametersGenerator.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/PBEParametersGenerator.java	2012-07-27 18:48:00.021478751 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/PBEParametersGenerator.java bcprov-jdk15on-147/org/bouncycastle/crypto/PBEParametersGenerator.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/PBEParametersGenerator.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/PBEParametersGenerator.java	2012-09-11 00:12:44.000000000 +0000
 @@ -136,7 +136,8 @@
      public static byte[] PKCS12PasswordToBytes(
          char[]  password)
@@ -520,9 +517,9 @@
 +        // END android-changed
      }
  }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk16-146/org/bouncycastle/crypto/digests/OpenSSLDigest.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2012-07-27 18:48:00.021478751 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk15on-147/org/bouncycastle/crypto/digests/OpenSSLDigest.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2012-09-11 00:12:44.000000000 +0000
 @@ -0,0 +1,159 @@
 +/*
 + * Copyright (C) 2008 The Android Open Source Project
@@ -683,19 +680,75 @@
 +        public SHA512() { super("SHA-512", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +}
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/engines/RC2Engine.java bcprov-jdk16-146/org/bouncycastle/crypto/engines/RC2Engine.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/engines/RC2Engine.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/engines/RC2Engine.java	2012-07-27 18:48:00.011478563 +0000
-@@ -313,4 +313,4 @@
-         out[outOff + 6] = (byte)x76;
-         out[outOff + 7] = (byte)(x76 >> 8);
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/encodings/OAEPEncoding.java bcprov-jdk15on-147/org/bouncycastle/crypto/encodings/OAEPEncoding.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/encodings/OAEPEncoding.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/encodings/OAEPEncoding.java	2012-09-11 00:12:44.000000000 +0000
+@@ -4,7 +4,9 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.InvalidCipherTextException;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ import org.bouncycastle.crypto.params.ParametersWithRandom;
+ 
+ import java.security.SecureRandom;
+@@ -26,7 +28,9 @@
+     public OAEPEncoding(
+         AsymmetricBlockCipher   cipher)
+     {
+-        this(cipher, new SHA1Digest(), null);
++        // BEGIN android-changed
++        this(cipher, new OpenSSLDigest.SHA1(), null);
++        // END android-changed
      }
--}
-+}
-\ No newline at end of file
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java bcprov-jdk16-146/org/bouncycastle/crypto/generators/DHParametersHelper.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/generators/DHParametersHelper.java	2012-07-27 18:48:00.021478751 +0000
+     
+     public OAEPEncoding(
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/encodings/PKCS1Encoding.java bcprov-jdk15on-147/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/encodings/PKCS1Encoding.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/encodings/PKCS1Encoding.java	2012-09-11 00:12:44.000000000 +0000
+@@ -206,6 +206,12 @@
+         {
+             throw new InvalidCipherTextException("unknown block type");
+         }
++        // BEGIN android-added
++        if ((type == 1 && forPrivateKey) || (type == 2 && !forPrivateKey))
++        {
++            throw new InvalidCipherTextException("invalid block type " + type);
++        }
++        // END android-added
+ 
+         if (useStrictLength && block.length != engine.getOutputBlockSize())
+         {
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/engines/DESedeWrapEngine.java bcprov-jdk15on-147/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/engines/DESedeWrapEngine.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/engines/DESedeWrapEngine.java	2012-09-11 00:12:44.000000000 +0000
+@@ -6,7 +6,9 @@
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.InvalidCipherTextException;
+ import org.bouncycastle.crypto.Wrapper;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ import org.bouncycastle.crypto.modes.CBCBlockCipher;
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+@@ -52,7 +54,9 @@
+     //
+     // checksum digest
+     //
+-    Digest  sha1 = new SHA1Digest();
++    // BEGIN android-changed
++    Digest  sha1 = new OpenSSLDigest.SHA1();
++    // END android-changed
+     byte[]  digest = new byte[20];
+ 
+    /**
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java bcprov-jdk15on-147/org/bouncycastle/crypto/generators/DHParametersHelper.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/generators/DHParametersHelper.java	2012-09-11 00:12:44.000000000 +0000
 @@ -3,10 +3,17 @@
  import java.math.BigInteger;
  import java.security.SecureRandom;
@@ -746,16 +799,102 @@
  
          return new BigInteger[] { p, q };
      }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk16-146/org/bouncycastle/crypto/macs/HMac.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/macs/HMac.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/macs/HMac.java	2012-07-27 18:48:00.021478751 +0000
-@@ -32,23 +32,23 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/DSAParametersGenerator.java bcprov-jdk15on-147/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/DSAParametersGenerator.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/generators/DSAParametersGenerator.java	2012-09-11 00:12:44.000000000 +0000
+@@ -1,8 +1,9 @@
+ package org.bouncycastle.crypto.generators;
+ 
+ import org.bouncycastle.crypto.Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ import org.bouncycastle.crypto.params.DSAParameters;
+ import org.bouncycastle.crypto.params.DSAValidationParameters;
+ import org.bouncycastle.util.Arrays;
+@@ -75,7 +76,9 @@
+         byte[]          part1 = new byte[20];
+         byte[]          part2 = new byte[20];
+         byte[]          u = new byte[20];
+-        SHA1Digest      sha1 = new SHA1Digest();
++        // BEGIN android-changed
++        Digest          sha1 = new OpenSSLDigest.SHA1();
++        // END android-changed
+         int             n = (L - 1) / 160;
+         byte[]          w = new byte[L / 8];
+ 
+@@ -166,7 +169,9 @@
+     {
+ // A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+         // FIXME This should be configurable (digest size in bits must be >= N)
+-        Digest d = new SHA256Digest();
++        // BEGIN android-changed
++        Digest d = new OpenSSLDigest.SHA256();
++        // END android-changed
+         int outlen = d.getDigestSize() * 8;
+ 
+ // 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java bcprov-jdk15on-147/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java	2012-09-11 00:12:44.000000000 +0000
+@@ -3,7 +3,9 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.PBEParametersGenerator;
+-import org.bouncycastle.crypto.digests.MD5Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+ 
+@@ -17,7 +19,9 @@
+ public class OpenSSLPBEParametersGenerator
+     extends PBEParametersGenerator
+ {
+-    private Digest  digest = new MD5Digest();
++    // BEGIN android-changed
++    private Digest  digest = new OpenSSLDigest.MD5();
++    // END android-changed
+ 
+     /**
+      * Construct a OpenSSL Parameters generator. 
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java bcprov-jdk15on-147/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java	2012-09-11 00:12:44.000000000 +0000
+@@ -4,7 +4,9 @@
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.Mac;
+ import org.bouncycastle.crypto.PBEParametersGenerator;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
++// BEGIN android-changed
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-changed
+ import org.bouncycastle.crypto.macs.HMac;
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+@@ -27,7 +29,9 @@
+      */
+     public PKCS5S2ParametersGenerator()
+     {
+-    	this(new SHA1Digest());
++        // BEGIN android-changed
++    	this(new OpenSSLDigest.SHA1());
++        // END android-changed
+     }
+ 
+     public PKCS5S2ParametersGenerator(Digest digest)
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk15on-147/org/bouncycastle/crypto/macs/HMac.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/macs/HMac.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/macs/HMac.java	2012-09-11 00:12:44.000000000 +0000
+@@ -32,23 +32,31 @@
      {
          blockLengths = new Hashtable();
          
 -        blockLengths.put("GOST3411", new Integer(32));
-+        blockLengths.put("GOST3411", Integer.valueOf(32));
-         
+-        
 -        blockLengths.put("MD2", new Integer(16));
 -        blockLengths.put("MD4", new Integer(64));
 -        blockLengths.put("MD5", new Integer(64));
@@ -768,30 +907,59 @@
 -        blockLengths.put("SHA-256", new Integer(64));
 -        blockLengths.put("SHA-384", new Integer(128));
 -        blockLengths.put("SHA-512", new Integer(128));
-+        blockLengths.put("MD2", Integer.valueOf(16));
-+        blockLengths.put("MD4", Integer.valueOf(64));
+-        
+-        blockLengths.put("Tiger", new Integer(64));
+-        blockLengths.put("Whirlpool", new Integer(64));
++        // BEGIN android-removed
++        // blockLengths.put("GOST3411", Integer.valueOf(32));
++        //
++        // blockLengths.put("MD2", Integer.valueOf(16));
++        // blockLengths.put("MD4", Integer.valueOf(64));
++        // END android-removed
 +        blockLengths.put("MD5", Integer.valueOf(64));
 +        
-+        blockLengths.put("RIPEMD128", Integer.valueOf(64));
-+        blockLengths.put("RIPEMD160", Integer.valueOf(64));
++        // BEGIN android-removed
++        // blockLengths.put("RIPEMD128", Integer.valueOf(64));
++        // blockLengths.put("RIPEMD160", Integer.valueOf(64));
++        // END android-removed
 +        
 +        blockLengths.put("SHA-1", Integer.valueOf(64));
-+        blockLengths.put("SHA-224", Integer.valueOf(64));
++        // BEGIN android-removed
++        // blockLengths.put("SHA-224", Integer.valueOf(64));
++        // END android-removed
 +        blockLengths.put("SHA-256", Integer.valueOf(64));
 +        blockLengths.put("SHA-384", Integer.valueOf(128));
 +        blockLengths.put("SHA-512", Integer.valueOf(128));
-         
--        blockLengths.put("Tiger", new Integer(64));
--        blockLengths.put("Whirlpool", new Integer(64));
-+        blockLengths.put("Tiger", Integer.valueOf(64));
-+        blockLengths.put("Whirlpool", Integer.valueOf(64));
++        
++        // BEGIN android-removed
++        // blockLengths.put("Tiger", Integer.valueOf(64));
++        // blockLengths.put("Whirlpool", Integer.valueOf(64));
++        // END android-removed
      }
      
      private static int getByteLength(
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk16-146/org/bouncycastle/crypto/signers/RSADigestSigner.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/signers/RSADigestSigner.java	2012-07-27 18:48:00.021478751 +0000
-@@ -46,8 +46,10 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk15on-147/org/bouncycastle/crypto/signers/RSADigestSigner.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/signers/RSADigestSigner.java	2012-09-11 00:12:44.000000000 +0000
+@@ -39,18 +39,24 @@
+      */
+     static
+     {
+-        oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+-        oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+-        oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
++        // BEGIN android-removed
++        // oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
++        // oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
++        // oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
++        // 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-384", NISTObjectIdentifiers.id_sha384);
          oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
  
@@ -804,12 +972,12 @@
          oidMap.put("MD5", PKCSObjectIdentifiers.md5);
      }
  
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk16-146/org/bouncycastle/crypto/util/PrivateKeyFactory.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2012-07-27 18:48:00.031478939 +0000
-@@ -12,7 +12,9 @@
- import org.bouncycastle.asn1.DERObject;
- import org.bouncycastle.asn1.DERObjectIdentifier;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk15on-147/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2012-09-11 00:12:44.000000000 +0000
+@@ -11,7 +11,9 @@
+ import org.bouncycastle.asn1.ASN1Sequence;
+ import org.bouncycastle.asn1.DERInteger;
  import org.bouncycastle.asn1.nist.NISTNamedCurves;
 -import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// BEGIN android-removed
@@ -818,9 +986,9 @@
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.DHParameter;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-@@ -20,7 +22,9 @@
- import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
- import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+@@ -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
@@ -829,7 +997,7 @@
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.DSAParameter;
  import org.bouncycastle.asn1.x9.X962NamedCurves;
-@@ -34,8 +38,10 @@
+@@ -33,8 +37,10 @@
  import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
  import org.bouncycastle.crypto.params.ECDomainParameters;
  import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
@@ -842,55 +1010,53 @@
  import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
  
  /**
-@@ -103,15 +109,17 @@
+@@ -100,14 +106,16 @@
  
              return new DHPrivateKeyParameters(derX.getValue(), dhParams);
          }
--        else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+-        else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 -        {
--            ElGamalParameter params = new ElGamalParameter(
--                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
--            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
+-            ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+-            DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
 -
 -            return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
 -                params.getP(), params.getG()));
 -        }
 +        // BEGIN android-removed
-+        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
++        // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 +        // {
-+        //     ElGamalParameter params = new ElGamalParameter(
-+        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-+        //     DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
++        //     ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
++        //     DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
 +        //
 +        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
 +        //         params.getP(), params.getG()));
 +        // }
 +        // END android-removed
-         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
+         else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa))
          {
-             DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
-@@ -145,10 +153,12 @@
+             DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
+@@ -140,10 +148,12 @@
                      {
-                         ecP = NISTNamedCurves.getByOID(oid);
+                         x9 = NISTNamedCurves.getByOID(oid);
  
--                        if (ecP == null)
+-                        if (x9 == null)
 -                        {
--                            ecP = TeleTrusTNamedCurves.getByOID(oid);
+-                            x9 = TeleTrusTNamedCurves.getByOID(oid);
 -                        }
 +                        // BEGIN android-removed
-+                        // if (ecP == null)
++                        // if (x9 == null)
 +                        // {
-+                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
++                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
 +                        // }
 +                        // END android-removed
                      }
                  }
- 
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk16-146/org/bouncycastle/crypto/util/PublicKeyFactory.java
---- bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/crypto/util/PublicKeyFactory.java	2012-07-27 18:48:00.031478939 +0000
-@@ -15,12 +15,16 @@
- import org.bouncycastle.asn1.DERObjectIdentifier;
+             }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk15on-147/org/bouncycastle/crypto/util/PublicKeyFactory.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/crypto/util/PublicKeyFactory.java	2012-09-11 00:12:44.000000000 +0000
+@@ -13,13 +13,17 @@
+ import org.bouncycastle.asn1.DERInteger;
  import org.bouncycastle.asn1.DEROctetString;
  import org.bouncycastle.asn1.nist.NISTNamedCurves;
 -import org.bouncycastle.asn1.oiw.ElGamalParameter;
@@ -900,6 +1066,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
@@ -907,8 +1074,8 @@
 +// END android-removed
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.DSAParameter;
- import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
-@@ -42,8 +46,10 @@
+ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+@@ -40,8 +44,10 @@
  import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
  import org.bouncycastle.crypto.params.ECDomainParameters;
  import org.bouncycastle.crypto.params.ECPublicKeyParameters;
@@ -921,55 +1088,4665 @@
  import org.bouncycastle.crypto.params.RSAKeyParameters;
  
  /**
-@@ -139,15 +145,17 @@
+@@ -135,14 +141,16 @@
  
              return new DHPublicKeyParameters(derY.getValue(), dhParams);
          }
--        else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+-        else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 -        {
--            ElGamalParameter params = new ElGamalParameter(
--                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
--            DERInteger derY = (DERInteger)keyInfo.getPublicKey();
+-            ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+-            DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
 -
 -            return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
 -                params.getP(), params.getG()));
 -        }
 +        // BEGIN android-removed
-+        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
++        // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 +        // {
-+        //     ElGamalParameter params = new ElGamalParameter(
-+        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-+        //     DERInteger derY = (DERInteger)keyInfo.getPublicKey();
++        //     ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
++        //     DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
 +        //
 +        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
 +        //         params.getP(), params.getG()));
 +        // }
 +        // END android-removed
-         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa)
-             || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
+         else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
+             || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1))
          {
-@@ -182,10 +190,12 @@
+@@ -177,10 +185,12 @@
                      {
-                         ecP = NISTNamedCurves.getByOID(oid);
+                         x9 = NISTNamedCurves.getByOID(oid);
  
--                        if (ecP == null)
+-                        if (x9 == null)
 -                        {
--                            ecP = TeleTrusTNamedCurves.getByOID(oid);
+-                            x9 = TeleTrusTNamedCurves.getByOID(oid);
 -                        }
 +                        // BEGIN android-removed
-+                        // if (ecP == null)
++                        // if (x9 == null)
 +                        // {
-+                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
++                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
 +                        // }
 +                        // END android-removed
                      }
                  }
+             }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/DSA.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/DSA.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/DSA.java	2012-09-11 00:12:44.000000000 +0000
+@@ -27,26 +27,34 @@
+             provider.addAlgorithm("KeyPairGenerator.DSA", PREFIX + "KeyPairGeneratorSpi");
+             provider.addAlgorithm("KeyFactory.DSA", PREFIX + "KeyFactorySpi");
  
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/ECNamedCurveTable.java bcprov-jdk16-146/org/bouncycastle/jce/ECNamedCurveTable.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/ECNamedCurveTable.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/ECNamedCurveTable.java	2012-07-27 18:48:00.031478939 +0000
+-            provider.addAlgorithm("Signature.DSA", PREFIX + "DSASigner$stdDSA");
++            // BEGIN android-changed
++            provider.addAlgorithm("Signature.SHA1withDSA", PREFIX + "DSASigner$stdDSA");
++            // END android-changed
+             provider.addAlgorithm("Signature.NONEWITHDSA", PREFIX + "DSASigner$noneDSA");
+ 
+             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);
+-            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");
+-            provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "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
++
++            // BEGIN android-added
++            provider.addAlgorithm("Alg.Alias.Signature.DSA", "SHA1withDSA");
++            // 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.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
++            // END android-changed
+ 
+             AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+ 
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/EC.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/EC.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/EC.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/EC.java	2012-09-11 00:12:44.000000000 +0000
+@@ -1,7 +1,9 @@
+ package org.bouncycastle.jcajce.provider.asymmetric;
+ 
+-import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
++// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// END android-removed
+ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+ import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi;
+ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+@@ -21,33 +23,43 @@
+         public void configure(ConfigurableProvider provider)
+         {
+             provider.addAlgorithm("KeyAgreement.ECDH", PREFIX + "KeyAgreementSpi$DH");
+-            provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC");
+-            provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV");
+-            provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDF");
+-            provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF");
++            // BEGIN android-removed
++            // provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC");
++            // provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV");
++            // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDF");
++            // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF");
++            // END android-removed
+ 
+             registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC());
+             // TODO Should this be an alias for ECDH?
+             registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+-            registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+-
+-            registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC");
+-            // TODO Should this be an alias for ECDH?
+-            registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+-            registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC");
++            // BEGIN android-removed
++            // registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
++            // END android-removed
++
++            // BEGIN android-removed
++            // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC");
++            // // TODO Should this be an alias for ECDH?
++            // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
++            // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC");
++            // END android-removed
+ 
+             provider.addAlgorithm("KeyFactory.EC", PREFIX + "KeyFactorySpi$EC");
+-            provider.addAlgorithm("KeyFactory.ECDSA", PREFIX + "KeyFactorySpi$ECDSA");
+-            provider.addAlgorithm("KeyFactory.ECDH", PREFIX + "KeyFactorySpi$ECDH");
+-            provider.addAlgorithm("KeyFactory.ECDHC", PREFIX + "KeyFactorySpi$ECDHC");
+-            provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV");
++            // BEGIN android-removed
++            // provider.addAlgorithm("KeyFactory.ECDSA", PREFIX + "KeyFactorySpi$ECDSA");
++            // provider.addAlgorithm("KeyFactory.ECDH", PREFIX + "KeyFactorySpi$ECDH");
++            // provider.addAlgorithm("KeyFactory.ECDHC", PREFIX + "KeyFactorySpi$ECDHC");
++            // provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV");
++            // END android-removed
+ 
+             provider.addAlgorithm("KeyPairGenerator.EC", PREFIX + "KeyPairGeneratorSpi$EC");
+-            provider.addAlgorithm("KeyPairGenerator.ECDSA", PREFIX + "KeyPairGeneratorSpi$ECDSA");
+-            provider.addAlgorithm("KeyPairGenerator.ECDH", PREFIX + "KeyPairGeneratorSpi$ECDH");
+-            provider.addAlgorithm("KeyPairGenerator.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC");
+-            provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
+-            provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV");
++            // BEGIN android-removed
++            // provider.addAlgorithm("KeyPairGenerator.ECDSA", PREFIX + "KeyPairGeneratorSpi$ECDSA");
++            // provider.addAlgorithm("KeyPairGenerator.ECDH", PREFIX + "KeyPairGeneratorSpi$ECDH");
++            // provider.addAlgorithm("KeyPairGenerator.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC");
++            // provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
++            // provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV");
++            // END android-removed
+ 
+             provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA");
+             provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone");
+@@ -59,23 +71,29 @@
+             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);
++            // BEGIN android-removed
++            // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
++            // END android-removed
++
++            // BEGIN android-removed
++            // addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
++            // END android-removed
+             addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+             addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+             addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+-            addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+-
+-            provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
+-            provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224");
+-            provider.addAlgorithm("Signature.SHA256WITHECNR", PREFIX + "SignatureSpi$ecNR256");
+-            provider.addAlgorithm("Signature.SHA384WITHECNR", PREFIX + "SignatureSpi$ecNR384");
+-            provider.addAlgorithm("Signature.SHA512WITHECNR", PREFIX + "SignatureSpi$ecNR512");
+-
+-            addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+-            addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+-            addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
++            // BEGIN android-removed
++            // addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
++            //
++            // provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
++            // provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224");
++            // provider.addAlgorithm("Signature.SHA256WITHECNR", PREFIX + "SignatureSpi$ecNR256");
++            // provider.addAlgorithm("Signature.SHA384WITHECNR", PREFIX + "SignatureSpi$ecNR384");
++            // provider.addAlgorithm("Signature.SHA512WITHECNR", PREFIX + "SignatureSpi$ecNR512");
++            //
++            // addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
++            // addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
++            // addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
++            // END android-removed
+         }
+     }
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/RSA.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/RSA.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/RSA.java	2012-09-11 00:12:44.000000000 +0000
 @@ -3,7 +3,9 @@
+ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// END android-removed
+ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+ import org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi;
+ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+@@ -24,41 +26,49 @@
+         public void configure(ConfigurableProvider provider)
+         {
+             provider.addAlgorithm("AlgorithmParameters.OAEP", PREFIX + "AlgorithmParametersSpi$OAEP");
+-            provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS");
+-
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
+-
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
+-
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAANDMGF1", "PSS");
++            // BEGIN android-removed
++            // provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS");
++            //
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
++            //
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
++            //
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAANDMGF1", "PSS");
++            // END android-removed
+ 
+             provider.addAlgorithm("Cipher.RSA", PREFIX + "CipherSpi$NoPadding");
+-            provider.addAlgorithm("Cipher.RSA/RAW", PREFIX + "CipherSpi$NoPadding");
+-            provider.addAlgorithm("Cipher.RSA/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+-            provider.addAlgorithm("Cipher.1.2.840.113549.1.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+-            provider.addAlgorithm("Cipher.2.5.8.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+-            provider.addAlgorithm("Cipher.RSA/1", PREFIX + "CipherSpi$PKCS1v1_5Padding_PrivateOnly");
+-            provider.addAlgorithm("Cipher.RSA/2", PREFIX + "CipherSpi$PKCS1v1_5Padding_PublicOnly");
+-            provider.addAlgorithm("Cipher.RSA/OAEP", PREFIX + "CipherSpi$OAEPPadding");
+-            provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding");
+-            provider.addAlgorithm("Cipher.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding");
++            // BEGIN android-changed
++            provider.addAlgorithm("Alg.Alias.Cipher.RSA/RAW", "RSA");
++            // END android-changed
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher.RSA/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
++            // provider.addAlgorithm("Cipher.1.2.840.113549.1.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
++            // provider.addAlgorithm("Cipher.2.5.8.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
++            // provider.addAlgorithm("Cipher.RSA/1", PREFIX + "CipherSpi$PKCS1v1_5Padding_PrivateOnly");
++            // provider.addAlgorithm("Cipher.RSA/2", PREFIX + "CipherSpi$PKCS1v1_5Padding_PublicOnly");
++            // provider.addAlgorithm("Cipher.RSA/OAEP", PREFIX + "CipherSpi$OAEPPadding");
++            // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding");
++            // provider.addAlgorithm("Cipher.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding");
++            // END android-removed
+ 
+             provider.addAlgorithm("Alg.Alias.Cipher.RSA//RAW", "RSA");
+             provider.addAlgorithm("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
+-            provider.addAlgorithm("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
+-            provider.addAlgorithm("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
+-            provider.addAlgorithm("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
++            // provider.addAlgorithm("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
++            // provider.addAlgorithm("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
++            // END android-removed
+ 
+             provider.addAlgorithm("KeyFactory.RSA", PREFIX + "KeyFactorySpi");
+             provider.addAlgorithm("KeyPairGenerator.RSA", PREFIX + "KeyPairGeneratorSpi");
+@@ -68,101 +78,111 @@
+             registerOid(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA", keyFact);
+             registerOid(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA", keyFact);
+             registerOid(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA", keyFact);
+-            registerOid(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "RSA", keyFact);
+-
+-            registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA");
+-            registerOidAlgorithmParameters(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA");
+-            registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
+-            registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
+-
+-
+-            provider.addAlgorithm("Signature.RSASSA-PSS", PREFIX + "PSSSignatureSpi$PSSwithRSA");
+-            provider.addAlgorithm("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+-            provider.addAlgorithm("Signature.OID." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+-
+-            provider.addAlgorithm("Signature.SHA224withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA224withRSA");
+-            provider.addAlgorithm("Signature.SHA256withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA256withRSA");
+-            provider.addAlgorithm("Signature.SHA384withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA384withRSA");
+-            provider.addAlgorithm("Signature.SHA512withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA512withRSA");
+-
+-            provider.addAlgorithm("Signature.RSA", PREFIX + "DigestSignatureSpi$noneRSA");
+-            provider.addAlgorithm("Signature.RAWRSASSA-PSS", PREFIX + "PSSSignatureSpi$nonePSS");
+-
+-            provider.addAlgorithm("Alg.Alias.Signature.RAWRSA", "RSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSA", "RSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAANDMGF1", "RAWRSASSA-PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
+-
+-
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHRSAANDMGF1", "SHA224withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHRSAANDMGF1", "SHA256withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHRSAANDMGF1", "SHA384withRSA/PSS");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHRSAANDMGF1", "SHA512withRSA/PSS");
+-
+-            if (provider.hasAlgorithm("MessageDigest", "MD2"))
+-            {
+-                addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
+-            }
+-
+-            if (provider.hasAlgorithm("MessageDigest", "MD2"))
+-            {
+-                addDigestSignature(provider, "MD4", PREFIX + "DigestSignatureSpi$MD4", PKCSObjectIdentifiers.md4WithRSAEncryption);
+-            }
+-
+-            if (provider.hasAlgorithm("MessageDigest", "MD2"))
+-            {
+-                addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption);
+-                provider.addAlgorithm("Signature.MD5withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption");
+-                provider.addAlgorithm("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
+-            }
++            // BEGIN android-removed
++            // registerOid(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "RSA", keyFact);
++            //
++            // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA");
++            // registerOidAlgorithmParameters(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA");
++            // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
++            // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
++            //
++            //
++            // provider.addAlgorithm("Signature.RSASSA-PSS", PREFIX + "PSSSignatureSpi$PSSwithRSA");
++            // provider.addAlgorithm("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
++            // provider.addAlgorithm("Signature.OID." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
++            //
++            // provider.addAlgorithm("Signature.SHA224withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA224withRSA");
++            // provider.addAlgorithm("Signature.SHA256withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA256withRSA");
++            // provider.addAlgorithm("Signature.SHA384withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA384withRSA");
++            // provider.addAlgorithm("Signature.SHA512withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA512withRSA");
++            //
++            // provider.addAlgorithm("Signature.RSA", PREFIX + "DigestSignatureSpi$noneRSA");
++            // provider.addAlgorithm("Signature.RAWRSASSA-PSS", PREFIX + "PSSSignatureSpi$nonePSS");
++            //
++            // provider.addAlgorithm("Alg.Alias.Signature.RAWRSA", "RSA");
++            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSA", "RSA");
++            // provider.addAlgorithm("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAANDMGF1", "RAWRSASSA-PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
++            //
++            //
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHRSAANDMGF1", "SHA224withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHRSAANDMGF1", "SHA256withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHRSAANDMGF1", "SHA384withRSA/PSS");
++            // provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHRSAANDMGF1", "SHA512withRSA/PSS");
++            //
++            // if (provider.hasAlgorithm("MessageDigest", "MD2"))
++            // {
++            //     addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
++            // }
++            //
++            // if (provider.hasAlgorithm("MessageDigest", "MD2"))
++            // {
++            //     addDigestSignature(provider, "MD4", PREFIX + "DigestSignatureSpi$MD4", PKCSObjectIdentifiers.md4WithRSAEncryption);
++            // }
++            //
++            // if (provider.hasAlgorithm("MessageDigest", "MD2"))
++            // {
++            //     addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption);
++            //     provider.addAlgorithm("Signature.MD5withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption");
++            //     provider.addAlgorithm("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
++            // }
++            // END android-removed
+ 
+             if (provider.hasAlgorithm("MessageDigest", "SHA1"))
+             {
+-                provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
+-                provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
+-                provider.addAlgorithm("Signature.SHA1withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA1withRSA");
+-                provider.addAlgorithm("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
+-                provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHRSAANDMGF1", "SHA1withRSA/PSS");
++                // BEGIN android-removed
++                // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
++                // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
++                // provider.addAlgorithm("Signature.SHA1withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA1withRSA");
++                // provider.addAlgorithm("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
++                // provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHRSAANDMGF1", "SHA1withRSA/PSS");
++                // END android-removed
+ 
+                 addDigestSignature(provider, "SHA1", PREFIX + "DigestSignatureSpi$SHA1", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ 
+-                provider.addAlgorithm("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
+-                provider.addAlgorithm("Signature.SHA1withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption");
++                // BEGIN android-removed
++                // provider.addAlgorithm("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
++                // provider.addAlgorithm("Signature.SHA1withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption");
++                // END android-removed
+                 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);
+             addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+             addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ 
+-            if (provider.hasAlgorithm("MessageDigest", "RIPEMD128"))
+-            {
+-                addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+-                addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null);
+-            }
+-
+-            if (provider.hasAlgorithm("MessageDigest", "RIPEMD160"))
+-            {
+-                addDigestSignature(provider, "RIPEMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+-                addDigestSignature(provider, "RMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", null);
+-                provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
+-                provider.addAlgorithm("Signature.RIPEMD160withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$RIPEMD160WithRSAEncryption");
+-            }
+-
+-            if (provider.hasAlgorithm("MessageDigest", "RIPEMD256"))
+-            {
+-                addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+-                addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null);
+-            }
++            // BEGIN android-removed
++            // if (provider.hasAlgorithm("MessageDigest", "RIPEMD128"))
++            // {
++            //     addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
++            //     addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null);
++            // }
++            //
++            // if (provider.hasAlgorithm("MessageDigest", "RIPEMD160"))
++            // {
++            //     addDigestSignature(provider, "RIPEMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
++            //     addDigestSignature(provider, "RMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", null);
++            //     provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
++            //     provider.addAlgorithm("Signature.RIPEMD160withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$RIPEMD160WithRSAEncryption");
++            // }
++            //
++            // if (provider.hasAlgorithm("MessageDigest", "RIPEMD256"))
++            // {
++            //     addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
++            //     addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null);
++            // }
++            // END android-removed
+         }
+ 
+         private void addDigestSignature(
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/X509.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/X509.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/X509.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/X509.java	2012-09-11 00:12:44.000000000 +0000
+@@ -18,8 +18,10 @@
+ 
+         public void configure(ConfigurableProvider provider)
+         {
+-            provider.addAlgorithm("KeyFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory");
+-            provider.addAlgorithm("Alg.Alias.KeyFactory.X509", "X.509");
++            // BEGIN android-removed
++            // provider.addAlgorithm("KeyFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory");
++            // provider.addAlgorithm("Alg.Alias.KeyFactory.X509", "X.509");
++            // END android-removed
+ 
+             //
+             // certificate factories.
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -35,10 +35,12 @@
+ 
+     static
+     {
+-        Integer i64 = new Integer(64);
+-        Integer i192 = new Integer(192);
+-        Integer i128 = new Integer(128);
+-        Integer i256 = new Integer(256);
++        // BEGIN android-changed
++        Integer i64 = Integer.valueOf(64);
++        Integer i192 = Integer.valueOf(192);
++        Integer i128 = Integer.valueOf(128);
++        Integer i256 = Integer.valueOf(256);
++        // END android-changed
+ 
+         algorithms.put("DES", i64);
+         algorithms.put("DESEDE", i192);
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -63,7 +63,9 @@
+     {
+         if (!initialised)
+         {
+-            Integer paramStrength = new Integer(strength);
++            // BEGIN android-changed
++            Integer paramStrength = Integer.valueOf(strength);
++            // END android-changed
+ 
+             if (params.containsKey(paramStrength))
+             {
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java	2012-09-11 00:12:44.000000000 +0000
+@@ -23,11 +23,16 @@
+ import org.bouncycastle.crypto.DSA;
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.digests.NullDigest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.SHA384Digest;
+-import org.bouncycastle.crypto.digests.SHA512Digest;
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.SHA1Digest;
++// import org.bouncycastle.crypto.digests.SHA224Digest;
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.SHA384Digest;
++// import org.bouncycastle.crypto.digests.SHA512Digest;
++// END android-removed
+ import org.bouncycastle.crypto.params.ParametersWithRandom;
+ 
+ public class DSASigner
+@@ -228,45 +233,49 @@
+     {
+         public stdDSA()
+         {
+-            super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner());
++            // BEGIN android-changed
++            super(new OpenSSLDigest.SHA1(), new org.bouncycastle.crypto.signers.DSASigner());
++            // END android-changed
+         }
+     }
+ 
+-    static public class dsa224
+-        extends DSASigner
+-    {
+-        public dsa224()
+-        {
+-            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());
+-        }
+-    }
+-    
+-    static public class dsa384
+-        extends DSASigner
+-    {
+-        public dsa384()
+-        {
+-            super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+-        }
+-    }
+-    
+-    static public class dsa512
+-        extends DSASigner
+-    {
+-        public dsa512()
+-        {
+-            super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class dsa224
++    //     extends DSASigner
++    // {
++    //     public dsa224()
++    //     {
++    //         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());
++    //     }
++    // }
++    //
++    // static public class dsa384
++    //     extends DSASigner
++    // {
++    //     public dsa384()
++    //     {
++    //         super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner());
++    //     }
++    // }
++    //
++    // static public class dsa512
++    //     extends DSASigner
++    // {
++    //     public dsa512()
++    //     {
++    //         super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class noneDSA
+         extends DSASigner
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -20,7 +20,9 @@
+ 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.ECGOST3410NamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+@@ -222,21 +224,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());
+ 
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java	2012-09-11 00:12:44.000000000 +0000
+@@ -5,10 +5,14 @@
+ import java.security.PublicKey;
+ 
+ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+-import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// END android-removed
+ 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.params.AsymmetricKeyParameter;
+@@ -166,14 +170,16 @@
+             {
+                 oid = NISTNamedCurves.getOID(name);
+             }
+-            if (oid == null)
+-            {
+-                oid = TeleTrusTNamedCurves.getOID(name);
+-            }
+-            if (oid == null)
+-            {
+-                oid = ECGOST3410NamedCurves.getOID(name);
+-            }
++            // BEGIN android-removed
++            // if (oid == null)
++            // {
++            //     oid = TeleTrusTNamedCurves.getOID(name);
++            // }
++            // if (oid == null)
++            // {
++            //     oid = ECGOST3410NamedCurves.getOID(name);
++            // }
++            // END android-removed
+         }
+ 
+         return oid;
+@@ -191,10 +197,12 @@
+             {
+                 params = NISTNamedCurves.getByOID(oid);
+             }
+-            if (params == null)
+-            {
+-                params = TeleTrusTNamedCurves.getByOID(oid);
+-            }
++            // BEGIN android-removed
++            // if (params == null)
++            // {
++            //     params = TeleTrusTNamedCurves.getByOID(oid);
++            // }
++            // END android-removed
+         }
+ 
+         return params;
+@@ -212,14 +220,16 @@
+             {
+                 name = NISTNamedCurves.getName(oid);
+             }
+-            if (name == null)
+-            {
+-                name = TeleTrusTNamedCurves.getName(oid);
+-            }
+-            if (name == null)
+-            {
+-                name = ECGOST3410NamedCurves.getName(oid);
+-            }
++            // BEGIN android-removed
++            // if (name == null)
++            // {
++            //     name = TeleTrusTNamedCurves.getName(oid);
++            // }
++            // if (name == null)
++            // {
++            //     name = ECGOST3410NamedCurves.getName(oid);
++            // }
++            // END android-removed
+         }
+ 
+         return name;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -23,20 +23,26 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.DerivationFunction;
+ import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+-import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
+-import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
+-import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
+-import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
++// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
++// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
++// import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
++// END android-removed
+ import org.bouncycastle.crypto.digests.SHA1Digest;
+ import org.bouncycastle.crypto.params.ECDomainParameters;
+ import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+-import org.bouncycastle.crypto.params.MQVPrivateParameters;
+-import org.bouncycastle.crypto.params.MQVPublicParameters;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.params.MQVPrivateParameters;
++// import org.bouncycastle.crypto.params.MQVPublicParameters;
++// END android-removed
+ import org.bouncycastle.jce.interfaces.ECPrivateKey;
+ import org.bouncycastle.jce.interfaces.ECPublicKey;
+-import org.bouncycastle.jce.interfaces.MQVPrivateKey;
+-import org.bouncycastle.jce.interfaces.MQVPublicKey;
++// BEGIN android-removed
++// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
++// import org.bouncycastle.jce.interfaces.MQVPublicKey;
++// END android-removed
+ 
+ /**
+  * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+@@ -52,9 +58,11 @@
+ 
+     static
+     {
+-        Integer i128 = new Integer(128);
+-        Integer i192 = new Integer(192);
+-        Integer i256 = new Integer(256);
++        // BEGIN android-changed
++        Integer i128 = Integer.valueOf(128);
++        Integer i192 = Integer.valueOf(192);
++        Integer i256 = Integer.valueOf(256);
++        // END android-changed
+ 
+         algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+         algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+@@ -69,7 +77,9 @@
+     private BigInteger             result;
+     private ECDomainParameters     parameters;
+     private BasicAgreement         agreement;
+-    private DerivationFunction     kdf;
++    // BEGIN android-removed
++    // private DerivationFunction     kdf;
++    // END android-removed
+ 
+     private byte[] bigIntToBytes(
+         BigInteger    r)
+@@ -84,7 +94,9 @@
+     {
+         this.kaAlgorithm = kaAlgorithm;
+         this.agreement = agreement;
+-        this.kdf = kdf;
++        // BEGIN android-removed
++        // this.kdf = kdf;
++        // END android-removed
+     }
+ 
+     protected Key engineDoPhase(
+@@ -103,25 +115,27 @@
+         }
+ 
+         CipherParameters pubKey;        
+-        if (agreement instanceof ECMQVBasicAgreement)
+-        {
+-            if (!(key instanceof MQVPublicKey))
+-            {
+-                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+-                    + getSimpleName(MQVPublicKey.class) + " for doPhase");
+-            }
+-
+-            MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+-            ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+-                ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+-            ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+-                ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+-
+-            pubKey = new MQVPublicParameters(staticKey, ephemKey);
+-
+-            // TODO Validate that all the keys are using the same parameters?
+-        }
+-        else
++        // BEGIN android-removed
++        // if (agreement instanceof ECMQVBasicAgreement)
++        // {
++        //     if (!(key instanceof MQVPublicKey))
++        //     {
++        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
++        //             + getSimpleName(MQVPublicKey.class) + " for doPhase");
++        //     }
++        //
++        //     MQVPublicKey mqvPubKey = (MQVPublicKey)key;
++        //     ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
++        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
++        //     ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
++        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
++        //
++        //     pubKey = new MQVPublicParameters(staticKey, ephemKey);
++        //
++        //     // TODO Validate that all the keys are using the same parameters?
++        // }
++        // else
++        // END android-removed
+         {
+             if (!(key instanceof ECPublicKey))
+             {
+@@ -142,11 +156,13 @@
+     protected byte[] engineGenerateSecret()
+         throws IllegalStateException
+     {
+-        if (kdf != null)
+-        {
+-            throw new UnsupportedOperationException(
+-                "KDF can only be used when algorithm is known");
+-        }
++        // BEGIN android-removed
++        // if (kdf != null)
++        // {
++        //     throw new UnsupportedOperationException(
++        //         "KDF can only be used when algorithm is known");
++        // }
++        // END android-removed
+ 
+         return bigIntToBytes(result);
+     }
+@@ -174,23 +190,25 @@
+     {
+         byte[] secret = bigIntToBytes(result);
+ 
+-        if (kdf != null)
+-        {
+-            if (!algorithms.containsKey(algorithm))
+-            {
+-                throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+-            }
+-            
+-            int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
+-
+-            DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+-
+-            byte[] keyBytes = new byte[keySize / 8];
+-            kdf.init(params);
+-            kdf.generateBytes(keyBytes, 0, keyBytes.length);
+-            secret = keyBytes;
+-        }
+-        else
++        // BEGIN android-removed
++        // if (kdf != null)
++        // {
++        //     if (!algorithms.containsKey(algorithm))
++        //     {
++        //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
++        //     }
++        //  
++        //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
++        //
++        //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
++        //
++        //     byte[] keyBytes = new byte[keySize / 8];
++        //     kdf.init(params);
++        //     kdf.generateBytes(keyBytes, 0, keyBytes.length);
++        //     secret = keyBytes;
++        // }
++        // else
++        // END android-removed
+         {
+             // TODO Should we be ensuring the key is the right length?
+         }
+@@ -218,35 +236,37 @@
+     private void initFromKey(Key key)
+         throws InvalidKeyException
+     {
+-        if (agreement instanceof ECMQVBasicAgreement)
+-        {
+-            if (!(key instanceof MQVPrivateKey))
+-            {
+-                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+-                    + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+-            }
+-
+-            MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+-            ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+-                ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+-            ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+-                ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+-
+-            ECPublicKeyParameters ephemPubKey = null;
+-            if (mqvPrivKey.getEphemeralPublicKey() != null)
+-            {
+-                ephemPubKey = (ECPublicKeyParameters)
+-                    ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+-            }
+-
+-            MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+-            this.parameters = staticPrivKey.getParameters();
+-
+-            // TODO Validate that all the keys are using the same parameters?
+-
+-            agreement.init(localParams);
+-        }
+-        else
++        // BEGIN android-removed
++        // if (agreement instanceof ECMQVBasicAgreement)
++        // {
++        //     if (!(key instanceof MQVPrivateKey))
++        //     {
++        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
++        //             + getSimpleName(MQVPrivateKey.class) + " for initialisation");
++        //     }
++        //
++        //     MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
++        //     ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
++        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
++        //     ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
++        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
++        //
++        //     ECPublicKeyParameters ephemPubKey = null;
++        //     if (mqvPrivKey.getEphemeralPublicKey() != null)
++        //     {
++        //         ephemPubKey = (ECPublicKeyParameters)
++        //             ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
++        //     }
++        //
++        //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
++        //     this.parameters = staticPrivKey.getParameters();
++        //
++        //     // TODO Validate that all the keys are using the same parameters?
++        //
++        //     agreement.init(localParams);
++        // }
++        // else
++        // END android-removed
+         {
+             if (!(key instanceof ECPrivateKey))
+             {
+@@ -277,39 +297,41 @@
+         }
+     }
+ 
+-    public static class DHC
+-        extends KeyAgreementSpi
+-    {
+-        public DHC()
+-        {
+-            super("ECDHC", new ECDHCBasicAgreement(), null);
+-        }
+-    }
+-
+-    public static class MQV
+-        extends KeyAgreementSpi
+-    {
+-        public MQV()
+-        {
+-            super("ECMQV", new ECMQVBasicAgreement(), null);
+-        }
+-    }
+-
+-    public static class DHwithSHA1KDF
+-        extends KeyAgreementSpi
+-    {
+-        public DHwithSHA1KDF()
+-        {
+-            super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+-        }
+-    }
+-
+-    public static class MQVwithSHA1KDF
+-        extends KeyAgreementSpi
+-    {
+-        public MQVwithSHA1KDF()
+-        {
+-            super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class DHC
++    //     extends KeyAgreementSpi
++    // {
++    //     public DHC()
++    //     {
++    //         super("ECDHC", new ECDHCBasicAgreement(), null);
++    //     }
++    // }
++    //
++    // public static class MQV
++    //     extends KeyAgreementSpi
++    // {
++    //     public MQV()
++    //     {
++    //         super("ECMQV", new ECMQVBasicAgreement(), null);
++    //     }
++    // }
++    //
++    // public static class DHwithSHA1KDF
++    //     extends KeyAgreementSpi
++    // {
++    //     public DHwithSHA1KDF()
++    //     {
++    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
++    //     }
++    // }
++    //
++    // public static class MQVwithSHA1KDF
++    //     extends KeyAgreementSpi
++    // {
++    //     public MQVwithSHA1KDF()
++    //     {
++    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
++    //     }
++    // }
++    // END android-removed
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -200,14 +200,16 @@
+         }
+     }
+ 
+-    public static class ECGOST3410
+-        extends KeyFactorySpi
+-    {
+-        public ECGOST3410()
+-        {
+-            super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class ECGOST3410
++    //     extends KeyFactorySpi
++    // {
++    //     public ECGOST3410()
++    //     {
++    //         super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
++    //     }
++    // }
++    // END android-removed
+ 
+     public static class ECDH
+         extends KeyFactorySpi
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java	2012-09-11 00:12:44.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;
+@@ -55,13 +57,15 @@
+         static {
+             ecParameters = new Hashtable();
+ 
+-            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+-            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
+-            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+-
+-            ecParameters.put(new Integer(224), new ECGenParameterSpec("P-224"));
+-            ecParameters.put(new Integer(384), new ECGenParameterSpec("P-384"));
+-            ecParameters.put(new Integer(521), new ECGenParameterSpec("P-521"));
++            // BEGIN android-changed
++            ecParameters.put(Integer.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
++            ecParameters.put(Integer.valueOf(239), new ECGenParameterSpec("prime239v1"));
++            ecParameters.put(Integer.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
++
++            ecParameters.put(Integer.valueOf(224), new ECGenParameterSpec("P-224"));
++            ecParameters.put(Integer.valueOf(384), new ECGenParameterSpec("P-384"));
++            ecParameters.put(Integer.valueOf(521), new ECGenParameterSpec("P-521"));
++            // END android-changed
+         }
+ 
+         public EC()
+@@ -85,8 +89,16 @@
+             SecureRandom    random)
+         {
+             this.strength = strength;
++            // BEGIN android-added
++            if (random != null) {
++            // END android-added
+             this.random = random;
+-            ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(new Integer(strength));
++            // BEGIN android-added
++            }
++            // END android-added
++            // BEGIN android-changed
++            ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integer.valueOf(strength));
++            // END android-changed
+ 
+             if (ecParams != null)
+             {
+@@ -110,6 +122,11 @@
+             SecureRandom            random)
+             throws InvalidAlgorithmParameterException
+         {
++            // BEGIN android-added
++            if (random == null) {
++                random = this.random;
++            }
++            // END android-added
+             if (params instanceof ECParameterSpec)
+             {
+                 ECParameterSpec p = (ECParameterSpec)params;
+@@ -154,10 +171,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)
+@@ -173,10 +192,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);
+@@ -231,7 +252,15 @@
+         {
+             if (!initialised)
+             {
+-                throw new IllegalStateException("EC Key Pair Generator not initialised");
++                // BEGIN android-removed
++                // throw new IllegalStateException("EC Key Pair Generator not initialised");
++                // END android-removed
++                // BEGIN android-added
++                /*
++                 * KeyPairGenerator documentation says that a default initialization must be provided
++                 */
++                initialize(192, random);
++                // END android-added
+             }
+ 
+             AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -18,15 +18,22 @@
+ import org.bouncycastle.crypto.DSA;
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.digests.NullDigest;
+-import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.SHA384Digest;
+-import org.bouncycastle.crypto.digests.SHA512Digest;
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
++// import org.bouncycastle.crypto.digests.SHA1Digest;
++// import org.bouncycastle.crypto.digests.SHA224Digest;
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.SHA384Digest;
++// import org.bouncycastle.crypto.digests.SHA512Digest;
++// END android-removed
+ import org.bouncycastle.crypto.params.ParametersWithRandom;
+ import org.bouncycastle.crypto.signers.ECDSASigner;
+-import org.bouncycastle.crypto.signers.ECNRSigner;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.signers.ECNRSigner;
++// END android-removed
+ import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
+ import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder;
+ import org.bouncycastle.jce.interfaces.ECKey;
+@@ -108,7 +115,9 @@
+     {
+         public ecDSA()
+         {
+-            super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
++            // BEGIN android-changed
++            super(new OpenSSLDigest.SHA1(), new ECDSASigner(), new StdDSAEncoder());
++            // END android-changed
+         }
+     }
+ 
+@@ -121,21 +130,25 @@
+         }
+     }
+ 
+-    static public class ecDSA224
+-        extends SignatureSpi
+-    {
+-        public ecDSA224()
+-        {
+-            super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class ecDSA224
++    //     extends SignatureSpi
++    // {
++    //     public ecDSA224()
++    //     {
++    //         super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class ecDSA256
+         extends SignatureSpi
+     {
+         public ecDSA256()
+         {
+-            super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
++            // BEGIN android-changed
++            super(new OpenSSLDigest.SHA256(), new ECDSASigner(), new StdDSAEncoder());
++            // END android-changed
+         }
+     }
+ 
+@@ -144,7 +157,9 @@
+     {
+         public ecDSA384()
+         {
+-            super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
++            // BEGIN android-changed
++            super(new OpenSSLDigest.SHA384(), new ECDSASigner(), new StdDSAEncoder());
++            // END android-changed
+         }
+     }
+ 
+@@ -153,90 +168,94 @@
+     {
+         public ecDSA512()
+         {
+-            super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecDSARipeMD160
+-        extends SignatureSpi
+-    {
+-        public ecDSARipeMD160()
+-        {
+-            super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR
+-        extends SignatureSpi
+-    {
+-        public ecNR()
+-        {
+-            super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR224
+-        extends SignatureSpi
+-    {
+-        public ecNR224()
+-        {
+-            super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR256
+-        extends SignatureSpi
+-    {
+-        public ecNR256()
+-        {
+-            super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR384
+-        extends SignatureSpi
+-    {
+-        public ecNR384()
+-        {
+-            super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR512
+-        extends SignatureSpi
+-    {
+-        public ecNR512()
+-        {
+-            super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecCVCDSA
+-        extends SignatureSpi
+-    {
+-        public ecCVCDSA()
+-        {
+-            super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecCVCDSA224
+-        extends SignatureSpi
+-    {
+-        public ecCVCDSA224()
+-        {
+-            super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecCVCDSA256
+-        extends SignatureSpi
+-    {
+-        public ecCVCDSA256()
+-        {
+-            super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+-        }
+-    }
++            // BEGIN android-changed
++            super(new OpenSSLDigest.SHA512(), new ECDSASigner(), new StdDSAEncoder());
++            // END android-changed
++        }
++    }
++
++    // BEGIN android-removed
++    // static public class ecDSARipeMD160
++    //     extends SignatureSpi
++    // {
++    //     public ecDSARipeMD160()
++    //     {
++    //         super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR
++    //     extends SignatureSpi
++    // {
++    //     public ecNR()
++    //     {
++    //         super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR224
++    //     extends SignatureSpi
++    // {
++    //     public ecNR224()
++    //     {
++    //         super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR256
++    //     extends SignatureSpi
++    // {
++    //     public ecNR256()
++    //     {
++    //         super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR384
++    //     extends SignatureSpi
++    // {
++    //     public ecNR384()
++    //     {
++    //         super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR512
++    //     extends SignatureSpi
++    // {
++    //     public ecNR512()
++    //     {
++    //         super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecCVCDSA
++    //     extends SignatureSpi
++    // {
++    //     public ecCVCDSA()
++    //     {
++    //         super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecCVCDSA224
++    //     extends SignatureSpi
++    // {
++    //     public ecCVCDSA224()
++    //     {
++    //         super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecCVCDSA256
++    //     extends SignatureSpi
++    // {
++    //     public ecCVCDSA256()
++    //     {
++    //         super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     private static class StdDSAEncoder
+         implements DSAEncoder
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -55,11 +55,15 @@
+         {
+             AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                             DigestFactory.getOID(currentSpec.getDigestAlgorithm()),
+-                                                            new DERNull());
++                                                            // BEGIN android-changed
++                                                            DERNull.INSTANCE);
++                                                            // END android-changed
+             MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+             AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                             PKCSObjectIdentifiers.id_mgf1,
+-                                                            new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), new DERNull()));
++                                                            // BEGIN android-changed
++                                                            new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
++                                                            // END android-changed
+             PSource.PSpecified      pSource = (PSource.PSpecified)currentSpec.getPSource();
+             AlgorithmIdentifier pSourceAlgorithm = new AlgorithmIdentifier(
+                                                             PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+@@ -170,11 +174,15 @@
+             PSSParameterSpec pssSpec = currentSpec;
+             AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                 DigestFactory.getOID(pssSpec.getDigestAlgorithm()),
+-                                                new DERNull());
++                                                // BEGIN android-changed
++                                                DERNull.INSTANCE);
++                                                // END android-changed
+             MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+             AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                 PKCSObjectIdentifiers.id_mgf1,
+-                                                new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), new DERNull()));
++                                                // BEGIN android-changed
++                                                new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
++                                                // END android-changed
+             RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField()));
+             
+             return pssP.getEncoded("DER");
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -127,7 +127,9 @@
+      */
+     public byte[] getEncoded()
+     {
+-        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
++        // BEGIN android-changed
++        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
++        // END android-changed
+     }
+ 
+     /**
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -78,7 +78,9 @@
+ 
+     public byte[] getEncoded()
+     {
+-        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
++        // BEGIN android-changed
++        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
++        // END android-changed
+     }
+ 
+     public boolean equals(Object o)
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -89,7 +89,9 @@
+ 
+     public byte[] getEncoded()
+     {
+-        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
++        // BEGIN android-changed
++        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
++        // END android-changed
+     }
+ 
+     public int hashCode()
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -26,7 +26,9 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.InvalidCipherTextException;
+-import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
++// END android-removed
+ import org.bouncycastle.crypto.encodings.OAEPEncoding;
+ import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+ import org.bouncycastle.crypto.engines.RSABlindedEngine;
+@@ -197,10 +199,12 @@
+         {
+             cipher = new PKCS1Encoding(new RSABlindedEngine());
+         }
+-        else if (pad.equals("ISO9796-1PADDING"))
+-        {
+-            cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+-        }
++        // BEGIN android-removed
++        // else if (pad.equals("ISO9796-1PADDING"))
++        // {
++        //     cipher = new ISO9796d1Encoding(new RSABlindedEngine());
++        // }
++        // END android-removed
+         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));
+@@ -534,48 +540,50 @@
+         }
+     }
+ 
+-    static public class PKCS1v1_5Padding
+-        extends CipherSpi
+-    {
+-        public PKCS1v1_5Padding()
+-        {
+-            super(new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
+-    static public class PKCS1v1_5Padding_PrivateOnly
+-        extends CipherSpi
+-    {
+-        public PKCS1v1_5Padding_PrivateOnly()
+-        {
+-            super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
+-    static public class PKCS1v1_5Padding_PublicOnly
+-        extends CipherSpi
+-    {
+-        public PKCS1v1_5Padding_PublicOnly()
+-        {
+-            super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
+-    static public class OAEPPadding
+-        extends CipherSpi
+-    {
+-        public OAEPPadding()
+-        {
+-            super(OAEPParameterSpec.DEFAULT);
+-        }
+-    }
+-    
+-    static public class ISO9796d1Padding
+-        extends CipherSpi
+-    {
+-        public ISO9796d1Padding()
+-        {
+-            super(new ISO9796d1Encoding(new RSABlindedEngine()));
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class PKCS1v1_5Padding
++    //     extends CipherSpi
++    // {
++    //     public PKCS1v1_5Padding()
++    //     {
++    //         super(new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class PKCS1v1_5Padding_PrivateOnly
++    //     extends CipherSpi
++    // {
++    //     public PKCS1v1_5Padding_PrivateOnly()
++    //     {
++    //         super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class PKCS1v1_5Padding_PublicOnly
++    //     extends CipherSpi
++    // {
++    //     public PKCS1v1_5Padding_PublicOnly()
++    //     {
++    //         super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class OAEPPadding
++    //     extends CipherSpi
++    // {
++    //     public OAEPPadding()
++    //     {
++    //         super(OAEPParameterSpec.DEFAULT);
++    //     }
++    // }
++    //
++    // static public class ISO9796d1Padding
++    //     extends CipherSpi
++    // {
++    //     public ISO9796d1Padding()
++    //     {
++    //         super(new ISO9796d1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    // END android-removed
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -17,24 +17,31 @@
+ import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// END android-removed
+ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+ import org.bouncycastle.asn1.x509.DigestInfo;
+ import org.bouncycastle.crypto.AsymmetricBlockCipher;
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.Digest;
+-import org.bouncycastle.crypto.digests.MD2Digest;
+-import org.bouncycastle.crypto.digests.MD4Digest;
+-import org.bouncycastle.crypto.digests.MD5Digest;
+-import org.bouncycastle.crypto.digests.NullDigest;
+-import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD256Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.SHA384Digest;
+-import org.bouncycastle.crypto.digests.SHA512Digest;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.MD2Digest;
++// import org.bouncycastle.crypto.digests.MD4Digest;
++// import org.bouncycastle.crypto.digests.MD5Digest;
++// import org.bouncycastle.crypto.digests.NullDigest;
++// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
++// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
++// import org.bouncycastle.crypto.digests.RIPEMD256Digest;
++// import org.bouncycastle.crypto.digests.SHA1Digest;
++// import org.bouncycastle.crypto.digests.SHA224Digest;
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.SHA384Digest;
++// import org.bouncycastle.crypto.digests.SHA512Digest;
++// END android-removed
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
+ import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+ import org.bouncycastle.crypto.engines.RSABlindedEngine;
+ 
+@@ -261,25 +268,31 @@
+     {
+         public SHA1()
+         {
+-            super(OIWObjectIdentifiers.idSHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++            // BEGIN android-changed
++            super(OIWObjectIdentifiers.idSHA1, new OpenSSLDigest.SHA1(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
+ 
+-    static public class SHA224
+-        extends DigestSignatureSpi
+-    {
+-        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
+ 
+     static public class SHA256
+         extends DigestSignatureSpi
+     {
+         public SHA256()
+         {
+-            super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++            // BEGIN android-changed
++            super(NISTObjectIdentifiers.id_sha256, new OpenSSLDigest.SHA256(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
+ 
+@@ -288,7 +301,9 @@
+     {
+         public SHA384()
+         {
+-            super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++            // BEGIN android-changed
++            super(NISTObjectIdentifiers.id_sha384, new OpenSSLDigest.SHA384(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
+ 
+@@ -297,70 +312,78 @@
+     {
+         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, new OpenSSLDigest.SHA512(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
+ 
+-    static public class MD4
+-        extends DigestSignatureSpi
+-    {
+-        public MD4()
+-        {
+-            super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class MD2
++    //     extends DigestSignatureSpi
++    // {
++    //     public MD2()
++    //     {
++    //         super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class MD4
++    //     extends DigestSignatureSpi
++    // {
++    //     public MD4()
++    //     {
++    //         super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class MD5
+         extends DigestSignatureSpi
+     {
+         public MD5()
+         {
+-            super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++            // BEGIN android-changed
++            super(PKCSObjectIdentifiers.md5, new OpenSSLDigest.MD5(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
+ 
+-    static public class RIPEMD160
+-        extends DigestSignatureSpi
+-    {
+-        public RIPEMD160()
+-        {
+-            super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
+-    static public class RIPEMD128
+-        extends DigestSignatureSpi
+-    {
+-        public RIPEMD128()
+-        {
+-            super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
+-    static public class RIPEMD256
+-        extends DigestSignatureSpi
+-    {
+-        public RIPEMD256()
+-        {
+-            super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
+-    static public class noneRSA
+-        extends DigestSignatureSpi
+-    {
+-        public noneRSA()
+-        {
+-            super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class RIPEMD160
++    //     extends DigestSignatureSpi
++    // {
++    //     public RIPEMD160()
++    //     {
++    //         super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class RIPEMD128
++    //     extends DigestSignatureSpi
++    // {
++    //     public RIPEMD128()
++    //     {
++    //         super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class RIPEMD256
++    //     extends DigestSignatureSpi
++    // {
++    //     public RIPEMD256()
++    //     {
++    //         super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    //
++    // static public class noneRSA
++    //     extends DigestSignatureSpi
++    // {
++    //     public noneRSA()
++    //     {
++    //         super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
++    //     }
++    // }
++    // END android-removed
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java	2012-09-11 00:12:44.000000000 +0000
+@@ -18,8 +18,10 @@
+ import javax.crypto.NoSuchPaddingException;
+ import javax.crypto.spec.IvParameterSpec;
+ import javax.crypto.spec.PBEParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
+-import javax.crypto.spec.RC5ParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.RC2ParameterSpec;
++// import javax.crypto.spec.RC5ParameterSpec;
++// END android-removed
+ import javax.crypto.spec.SecretKeySpec;
+ 
+ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+@@ -37,8 +39,10 @@
+                                     {
+                                         IvParameterSpec.class,
+                                         PBEParameterSpec.class,
+-                                        RC2ParameterSpec.class,
+-                                        RC5ParameterSpec.class
++                                        // BEGIN android-removed
++                                        // RC2ParameterSpec.class,
++                                        // RC5ParameterSpec.class
++                                        // END android-removed
+                                     };
+ 
+ 
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java	2012-09-11 00:12:44.000000000 +0000
+@@ -36,7 +36,9 @@
+ import org.bouncycastle.asn1.pkcs.SignedData;
+ import org.bouncycastle.jce.provider.BouncyCastleProvider;
+ import org.bouncycastle.util.io.pem.PemObject;
+-import org.bouncycastle.util.io.pem.PemWriter;
++// BEGIN android-removed
++// import org.bouncycastle.util.io.pem.PemWriter;
++// END android-removed
+ 
+ /**
+  * CertPath implementation for X.509 certificates.
+@@ -298,27 +300,29 @@
+             return toDEREncoded(new ContentInfo(
+                     PKCSObjectIdentifiers.signedData, sd));
+         }
+-        else if (encoding.equalsIgnoreCase("PEM"))
+-        {
+-            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+-            PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+-
+-            try
+-            {
+-                for (int i = 0; i != certificates.size(); i++)
+-                {
+-                    pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+-                }
+-            
+-                pWrt.close();
+-            }
+-            catch (Exception e)
+-            {
+-                throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+-            }
+-
+-            return bOut.toByteArray();
+-        }
++        // BEGIN android-removed
++        // else if (encoding.equalsIgnoreCase("PEM"))
++        // {
++        //     ByteArrayOutputStream bOut = new ByteArrayOutputStream();
++        //     PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
++        //
++        //     try
++        //     {
++        //         for (int i = 0; i != certificates.size(); i++)
++        //         {
++        //             pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
++        //         }
++        //
++        //         pWrt.close();
++        //     }
++        //     catch (Exception e)
++        //     {
++        //         throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
++        //     }
++        //
++        //     return bOut.toByteArray();
++        // }
++        // END android-removed
+         else
+         {
+             throw new CertificateEncodingException("unsupported encoding: " + encoding);
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/AES.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/AES.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/AES.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/AES.java	2012-09-11 00:12:44.000000000 +0000
+@@ -1,31 +1,43 @@
+ package org.bouncycastle.jcajce.provider.symmetric;
+ 
+-import java.security.AlgorithmParameters;
+-import java.security.InvalidAlgorithmParameterException;
++// BEGIN android-removed
++// import java.security.AlgorithmParameters;
++// import java.security.InvalidAlgorithmParameterException;
++// END android-removed
+ import java.security.SecureRandom;
+-import java.security.spec.AlgorithmParameterSpec;
+-
+-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.nist.NISTObjectIdentifiers;
+ import org.bouncycastle.crypto.BufferedBlockCipher;
+ import org.bouncycastle.crypto.CipherKeyGenerator;
+ import org.bouncycastle.crypto.engines.AESFastEngine;
+ import org.bouncycastle.crypto.engines.AESWrapEngine;
+-import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+-import org.bouncycastle.crypto.macs.CMac;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// import org.bouncycastle.crypto.macs.CMac;
++// END android-removed
+ import org.bouncycastle.crypto.modes.CBCBlockCipher;
+ import org.bouncycastle.crypto.modes.CFBBlockCipher;
+ import org.bouncycastle.crypto.modes.OFBBlockCipher;
+ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+-import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
++// BEGIN android-removed
++// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
++// END android-removed
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+-import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
++// BEGIN android-removed
++// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
++// END android-removed
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+ import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+ import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+-import org.bouncycastle.jce.provider.BouncyCastleProvider;
++// BEGIN android-removed
++// import org.bouncycastle.jce.provider.BouncyCastleProvider;
++// END android-removed
+ 
+ public final class AES
+ {
+@@ -69,15 +81,17 @@
+         }
+     }
+ 
+-    public static class AESCMAC
+-        extends BaseMac
+-    {
+-        public AESCMAC()
+-        {
+-            super(new CMac(new AESFastEngine()));
+-        }
+-    }
+-
++    // BEGIN android-removed
++    // public static class AESCMAC
++    //     extends BaseMac
++    // {
++    //     public AESCMAC()
++    //     {
++    //         super(new CMac(new AESFastEngine()));
++    //     }
++    // }
++    // END android-removed
++    
+     static public class Wrap
+         extends BaseWrapCipher
+     {
+@@ -86,15 +100,17 @@
+             super(new AESWrapEngine());
+         }
+     }
+-
+-    public static class RFC3211Wrap
+-        extends BaseWrapCipher
+-    {
+-        public RFC3211Wrap()
+-        {
+-            super(new RFC3211WrapEngine(new AESFastEngine()), 16);
+-        }
+-    }
++    
++    // BEGIN android-removed
++    // public static class RFC3211Wrap
++    //     extends BaseWrapCipher
++    // {
++    //     public RFC3211Wrap()
++    //     {
++    //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
++    //     }
++    // }
++    // END android-removed
+ 
+     public static class KeyGen
+         extends BaseKeyGenerator
+@@ -110,70 +126,72 @@
+         }
+     }
+ 
+-    public static class KeyGen128
+-        extends KeyGen
+-    {
+-        public KeyGen128()
+-        {
+-            super(128);
+-        }
+-    }
+-
+-    public static class KeyGen192
+-        extends KeyGen
+-    {
+-        public KeyGen192()
+-        {
+-            super(192);
+-        }
+-    }
+-
+-    public static class KeyGen256
+-        extends KeyGen
+-    {
+-        public KeyGen256()
+-        {
+-            super(256);
+-        }
+-    }
+-
+-    public static class AlgParamGen
+-        extends BaseAlgorithmParameterGenerator
+-    {
+-        protected void engineInit(
+-            AlgorithmParameterSpec genParamSpec,
+-            SecureRandom random)
+-            throws InvalidAlgorithmParameterException
+-        {
+-            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+-        }
+-
+-        protected AlgorithmParameters engineGenerateParameters()
+-        {
+-            byte[]  iv = new byte[16];
+-
+-            if (random == null)
+-            {
+-                random = new SecureRandom();
+-            }
+-
+-            random.nextBytes(iv);
+-
+-            AlgorithmParameters params;
+-
+-            try
+-            {
+-                params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
+-                params.init(new IvParameterSpec(iv));
+-            }
+-            catch (Exception e)
+-            {
+-                throw new RuntimeException(e.getMessage());
+-            }
+-
+-            return params;
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class KeyGen128
++    //     extends KeyGen
++    // {
++    //     public KeyGen128()
++    //     {
++    //         super(128);
++    //     }
++    // }
++    //
++    // public static class KeyGen192
++    //     extends KeyGen
++    // {
++    //     public KeyGen192()
++    //     {
++    //         super(192);
++    //     }
++    // }
++    //
++    // public static class KeyGen256
++    //     extends KeyGen
++    // {
++    //     public KeyGen256()
++    //     {
++    //         super(256);
++    //     }
++    // }
++    //
++    // public static class AlgParamGen
++    //     extends BaseAlgorithmParameterGenerator
++    // {
++    //     protected void engineInit(
++    //         AlgorithmParameterSpec genParamSpec,
++    //         SecureRandom random)
++    //         throws InvalidAlgorithmParameterException
++    //     {
++    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
++    //     }
++    //
++    //     protected AlgorithmParameters engineGenerateParameters()
++    //     {
++    //         byte[]  iv = new byte[16];
++    //
++    //         if (random == null)
++    //         {
++    //             random = new SecureRandom();
++    //         }
++    //
++    //         random.nextBytes(iv);
++    //
++    //         AlgorithmParameters params;
++    //
++    //         try
++    //         {
++    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
++    //             params.init(new IvParameterSpec(iv));
++    //         }
++    //         catch (Exception e)
++    //         {
++    //             throw new RuntimeException(e.getMessage());
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    // END android-removed
+ 
+     public static class AlgParams
+         extends IvAlgorithmParameters
+@@ -212,58 +230,66 @@
+             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+ 
+-            provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
++            // BEGIN android-removed
++            // provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
++            // END android-removed
+ 
+             provider.addAlgorithm("Cipher.AES", PREFIX + "$ECB");
+             provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES128, "AES");
+             provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES192, "AES");
+             provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES256, "AES");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
+-            provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
++            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
++            // END android-removed
+             provider.addAlgorithm("Cipher.AESWRAP", PREFIX + "$Wrap");
+             provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+             provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+             provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+-            provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
++            // END android-removed
+ 
+             provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
+-            provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
+-            provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
+-            provider.addAlgorithm("KeyGenerator." + wrongAES256, PREFIX + "$KeyGen256");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
+-            provider.addAlgorithm("KeyGenerator.AESWRAP", PREFIX + "$KeyGen");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
+-            provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
+-
+-            provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
++            // BEGIN android-removed
++            // provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
++            // provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
++            // provider.addAlgorithm("KeyGenerator." + wrongAES256, PREFIX + "$KeyGen256");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
++            // provider.addAlgorithm("KeyGenerator.AESWRAP", PREFIX + "$KeyGen");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
++            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
++            //
++            // provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
++            // END android-removed
+         }
+     }
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/ARC4.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/ARC4.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/ARC4.java	2012-09-11 00:12:44.000000000 +0000
+@@ -27,7 +27,9 @@
+     {
+         public KeyGen()
+         {
+-            super("RC4", 128, new CipherKeyGenerator());
++            // BEGIN android-changed
++            super("ARC4", 128, new CipherKeyGenerator());
++            // END android-changed
+         }
+     }
+ 
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java	2012-09-11 00:12:44.000000000 +0000
+@@ -64,7 +64,9 @@
+         {
+ 
+             provider.addAlgorithm("Cipher.BLOWFISH", PREFIX + "$ECB");
+-            provider.addAlgorithm("Cipher.1.3.6.1.4.1.3029.1.2", PREFIX + "$CBC");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher.1.3.6.1.4.1.3029.1.2", PREFIX + "$CBC");
++            // END android-removed
+             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-147.orig/org/bouncycastle/jcajce/provider/symmetric/DES.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/DES.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/DES.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/DES.java	2012-09-11 00:12:44.000000000 +0000
+@@ -16,11 +16,15 @@
+ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+ import org.bouncycastle.crypto.KeyGenerationParameters;
+ import org.bouncycastle.crypto.engines.DESEngine;
+-import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// END android-removed
+ import org.bouncycastle.crypto.generators.DESKeyGenerator;
+ import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CMac;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
++// import org.bouncycastle.crypto.macs.CMac;
++// END android-removed
+ import org.bouncycastle.crypto.modes.CBCBlockCipher;
+ import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+@@ -48,115 +52,117 @@
+         }
+     }
+ 
+-    static public class CBC
+-        extends BaseBlockCipher
+-    {
+-        public CBC()
+-        {
+-            super(new CBCBlockCipher(new DESEngine()), 64);
+-        }
+-    }
+-
+-    /**
+-     * DES   CFB8
+-     */
+-    public static class DESCFB8
+-        extends BaseMac
+-    {
+-        public DESCFB8()
+-        {
+-            super(new CFBBlockCipherMac(new DESEngine()));
+-        }
+-    }
+-
+-    /**
+-     * DES64
+-     */
+-    public static class DES64
+-        extends BaseMac
+-    {
+-        public DES64()
+-        {
+-            super(new CBCBlockCipherMac(new DESEngine(), 64));
+-        }
+-    }
+-
+-    /**
+-     * DES64with7816-4Padding
+-     */
+-    public static class DES64with7816d4
+-        extends BaseMac
+-    {
+-        public DES64with7816d4()
+-        {
+-            super(new CBCBlockCipherMac(new DESEngine(), 64, new ISO7816d4Padding()));
+-        }
+-    }
+-    
+-    public static class CBCMAC
+-        extends BaseMac
+-    {
+-        public CBCMAC()
+-        {
+-            super(new CBCBlockCipherMac(new DESEngine()));
+-        }
+-    }
+-
+-    static public class CMAC
+-        extends BaseMac
+-    {
+-        public CMAC()
+-        {
+-            super(new CMac(new DESEngine()));
+-        }
+-    }
+-
+-    public static class RFC3211
+-        extends BaseWrapCipher
+-    {
+-        public RFC3211()
+-        {
+-            super(new RFC3211WrapEngine(new DESEngine()), 8);
+-        }
+-    }
+-
+-    public static class AlgParamGen
+-        extends BaseAlgorithmParameterGenerator
+-    {
+-        protected void engineInit(
+-            AlgorithmParameterSpec genParamSpec,
+-            SecureRandom            random)
+-            throws InvalidAlgorithmParameterException
+-        {
+-            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+-        }
+-
+-        protected AlgorithmParameters engineGenerateParameters()
+-        {
+-            byte[]  iv = new byte[8];
+-
+-            if (random == null)
+-            {
+-                random = new SecureRandom();
+-            }
+-
+-            random.nextBytes(iv);
+-
+-            AlgorithmParameters params;
+-
+-            try
+-            {
+-                params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+-                params.init(new IvParameterSpec(iv));
+-            }
+-            catch (Exception e)
+-            {
+-                throw new RuntimeException(e.getMessage());
+-            }
+-
+-            return params;
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class CBC
++    //     extends BaseBlockCipher
++    // {
++    //     public CBC()
++    //     {
++    //         super(new CBCBlockCipher(new DESEngine()), 64);
++    //     }
++    // }
++    //
++    // /**
++    //  * DES   CFB8
++    //  */
++    // public static class DESCFB8
++    //     extends BaseMac
++    // {
++    //     public DESCFB8()
++    //     {
++    //         super(new CFBBlockCipherMac(new DESEngine()));
++    //     }
++    // }
++    //
++    // /**
++    //  * DES64
++    //  */
++    // public static class DES64
++    //     extends BaseMac
++    // {
++    //     public DES64()
++    //     {
++    //         super(new CBCBlockCipherMac(new DESEngine(), 64));
++    //     }
++    // }
++    //
++    // /**
++    //  * DES64with7816-4Padding
++    //  */
++    // public static class DES64with7816d4
++    //     extends BaseMac
++    // {
++    //     public DES64with7816d4()
++    //     {
++    //         super(new CBCBlockCipherMac(new DESEngine(), 64, new ISO7816d4Padding()));
++    //     }
++    // }
++    //
++    // public static class CBCMAC
++    //     extends BaseMac
++    // {
++    //     public CBCMAC()
++    //     {
++    //         super(new CBCBlockCipherMac(new DESEngine()));
++    //     }
++    // }
++    //
++    // static public class CMAC
++    //     extends BaseMac
++    // {
++    //     public CMAC()
++    //     {
++    //         super(new CMac(new DESEngine()));
++    //     }
++    // }
++    //
++    // public static class RFC3211
++    //     extends BaseWrapCipher
++    // {
++    //     public RFC3211()
++    //     {
++    //         super(new RFC3211WrapEngine(new DESEngine()), 8);
++    //     }
++    // }
++    //
++    // public static class AlgParamGen
++    //     extends BaseAlgorithmParameterGenerator
++    // {
++    //     protected void engineInit(
++    //         AlgorithmParameterSpec genParamSpec,
++    //         SecureRandom            random)
++    //         throws InvalidAlgorithmParameterException
++    //     {
++    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
++    //     }
++    //
++    //     protected AlgorithmParameters engineGenerateParameters()
++    //     {
++    //         byte[]  iv = new byte[8];
++    //
++    //         if (random == null)
++    //         {
++    //             random = new SecureRandom();
++    //         }
++    //
++    //         random.nextBytes(iv);
++    //
++    //         AlgorithmParameters params;
++    //
++    //         try
++    //         {
++    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
++    //             params.init(new IvParameterSpec(iv));
++    //         }
++    //         catch (Exception e)
++    //         {
++    //             throw new RuntimeException(e.getMessage());
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    // END android-removed
+ 
+   /**
+      * DES - the default for this is to generate a key in
+@@ -263,36 +269,42 @@
+         {
+ 
+             provider.addAlgorithm("Cipher.DES", PREFIX + "$ECB");
+-            provider.addAlgorithm("Cipher." + OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
+-
+-            addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
+-
+-            provider.addAlgorithm("Cipher.DESRFC3211WRAP", PREFIX + "$RFC3211");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher." + OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
++            //
++            // addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
++            //
++            // provider.addAlgorithm("Cipher.DESRFC3211WRAP", PREFIX + "$RFC3211");
++            // END android-removed
+ 
+             provider.addAlgorithm("KeyGenerator.DES", PREFIX + "$KeyGenerator");
+ 
+             provider.addAlgorithm("SecretKeyFactory.DES", PREFIX + "$KeyFactory");
+ 
+-            provider.addAlgorithm("Mac.DESCMAC", PREFIX + "$CMAC");
+-            provider.addAlgorithm("Mac.DESMAC", PREFIX + "$CBCMAC");
+-            provider.addAlgorithm("Alg.Alias.Mac.DES", "DESMAC");
+-
+-            provider.addAlgorithm("Mac.DESMAC/CFB8", PREFIX + "$DESCFB8");
+-            provider.addAlgorithm("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
+-
+-            provider.addAlgorithm("Mac.DESMAC64", PREFIX + "$DES64");
+-            provider.addAlgorithm("Alg.Alias.Mac.DES64", "DESMAC64");
+-
+-            provider.addAlgorithm("Mac.DESMAC64WITHISO7816-4PADDING", PREFIX + "$DES64with7816d4");
+-            provider.addAlgorithm("Alg.Alias.Mac.DES64WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1MACWITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Mac.DESCMAC", PREFIX + "$CMAC");
++            // provider.addAlgorithm("Mac.DESMAC", PREFIX + "$CBCMAC");
++            // provider.addAlgorithm("Alg.Alias.Mac.DES", "DESMAC");
++            //
++            // provider.addAlgorithm("Mac.DESMAC/CFB8", PREFIX + "$DESCFB8");
++            // provider.addAlgorithm("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
++            //
++            // provider.addAlgorithm("Mac.DESMAC64", PREFIX + "$DES64");
++            // provider.addAlgorithm("Alg.Alias.Mac.DES64", "DESMAC64");
++            //
++            // provider.addAlgorithm("Mac.DESMAC64WITHISO7816-4PADDING", PREFIX + "$DES64with7816d4");
++            // provider.addAlgorithm("Alg.Alias.Mac.DES64WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1MACWITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
++            // END android-removed
+ 
+             provider.addAlgorithm("AlgorithmParameters.DES", PACKAGE + ".util.IvAlgorithmParameters");
+             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
+ 
+-            provider.addAlgorithm("AlgorithmParameterGenerator.DES",  PREFIX + "$AlgParamGen");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "DES");
++            // BEGIN android-removed
++            // provider.addAlgorithm("AlgorithmParameterGenerator.DES",  PREFIX + "$AlgParamGen");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "DES");
++            // END android-removed
+         }
+ 
+         private void addAlias(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/DESede.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/DESede.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/DESede.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/DESede.java	2012-09-11 00:12:44.000000000 +0000
+@@ -1,30 +1,42 @@
+ package org.bouncycastle.jcajce.provider.symmetric;
+ 
+-import java.security.AlgorithmParameters;
+-import java.security.InvalidAlgorithmParameterException;
++// BEGIN android-removed
++// import java.security.AlgorithmParameters;
++// import java.security.InvalidAlgorithmParameterException;
++// END android-removed
+ import java.security.SecureRandom;
+-import java.security.spec.AlgorithmParameterSpec;
++// BEGIN android-removed
++// import java.security.spec.AlgorithmParameterSpec;
++// END android-removed
+ import java.security.spec.InvalidKeySpecException;
+ import java.security.spec.KeySpec;
+ 
+ import javax.crypto.SecretKey;
+ import javax.crypto.spec.DESedeKeySpec;
+-import javax.crypto.spec.IvParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.IvParameterSpec;
++// END android-removed
+ import javax.crypto.spec.SecretKeySpec;
+ 
+ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+ import org.bouncycastle.crypto.KeyGenerationParameters;
+ import org.bouncycastle.crypto.engines.DESedeEngine;
+ import org.bouncycastle.crypto.engines.DESedeWrapEngine;
+-import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// END android-removed
+ import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+ import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CMac;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
++// import org.bouncycastle.crypto.macs.CMac;
++// END android-removed
+ import org.bouncycastle.crypto.modes.CBCBlockCipher;
+ import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+-import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
++// BEGIN android-removed
++// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
++// END android-removed
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+@@ -57,17 +69,19 @@
+         }
+     }
+ 
+-    /**
+-     * DESede   CFB8
+-     */
+-    public static class DESedeCFB8
+-        extends BaseMac
+-    {
+-        public DESedeCFB8()
+-        {
+-            super(new CFBBlockCipherMac(new DESedeEngine()));
+-        }
+-    }
++    // BEGIN android-removed
++    // /**
++    //  * DESede   CFB8
++    //  */
++    // public static class DESedeCFB8
++    //     extends BaseMac
++    // {
++    //     public DESedeCFB8()
++    //     {
++    //         super(new CFBBlockCipherMac(new DESedeEngine()));
++    //     }
++    // }
++    // END android-removed
+ 
+     /**
+      * DESede64
+@@ -102,15 +116,17 @@
+         }
+     }
+ 
+-    static public class CMAC
+-        extends BaseMac
+-    {
+-        public CMAC()
+-        {
+-            super(new CMac(new DESedeEngine()));
+-        }
+-    }
+-
++    // BEGIN android-removed
++    // static public class CMAC
++    //     extends BaseMac
++    // {
++    //     public CMAC()
++    //     {
++    //         super(new CMac(new DESedeEngine()));
++    //     }
++    // }
++    // END android-removed
++    
+     public static class Wrap
+         extends BaseWrapCipher
+     {
+@@ -119,15 +135,17 @@
+             super(new DESedeWrapEngine());
+         }
+     }
+-
+-    public static class RFC3211
+-        extends BaseWrapCipher
+-    {
+-        public RFC3211()
+-        {
+-            super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+-        }
+-    }
++    
++    // BEGIN android-removed
++    // public static class RFC3211
++    //     extends BaseWrapCipher
++    // {
++    //     public RFC3211()
++    //     {
++    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
++    //     }
++    // }
++    // END android-removed
+ 
+   /**
+      * DESede - the default for this is to generate a key in
+@@ -217,43 +235,45 @@
+         }
+     }
+ 
+-    public static class AlgParamGen
+-        extends BaseAlgorithmParameterGenerator
+-    {
+-        protected void engineInit(
+-            AlgorithmParameterSpec genParamSpec,
+-            SecureRandom            random)
+-            throws InvalidAlgorithmParameterException
+-        {
+-            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+-        }
+-
+-        protected AlgorithmParameters engineGenerateParameters()
+-        {
+-            byte[]  iv = new byte[8];
+-
+-            if (random == null)
+-            {
+-                random = new SecureRandom();
+-            }
+-
+-            random.nextBytes(iv);
+-
+-            AlgorithmParameters params;
+-
+-            try
+-            {
+-                params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+-                params.init(new IvParameterSpec(iv));
+-            }
+-            catch (Exception e)
+-            {
+-                throw new RuntimeException(e.getMessage());
+-            }
+-
+-            return params;
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class AlgParamGen
++    //     extends BaseAlgorithmParameterGenerator
++    // {
++    //     protected void engineInit(
++    //         AlgorithmParameterSpec genParamSpec,
++    //         SecureRandom            random)
++    //         throws InvalidAlgorithmParameterException
++    //     {
++    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
++    //     }
++    //
++    //     protected AlgorithmParameters engineGenerateParameters()
++    //     {
++    //         byte[]  iv = new byte[8];
++    //
++    //         if (random == null)
++    //         {
++    //             random = new SecureRandom();
++    //         }
++    //
++    //         random.nextBytes(iv);
++    //
++    //         AlgorithmParameters params;
++    //
++    //         try
++    //         {
++    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
++    //             params.init(new IvParameterSpec(iv));
++    //         }
++    //         catch (Exception e)
++    //         {
++    //             throw new RuntimeException(e.getMessage());
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class KeyFactory
+         extends BaseSecretKeyFactory
+@@ -337,18 +357,28 @@
+         public void configure(ConfigurableProvider provider)
+         {
+             provider.addAlgorithm("Cipher.DESEDE", PREFIX + "$ECB");
+-            provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
++            // END android-removed
+             provider.addAlgorithm("Cipher.DESEDEWRAP", PREFIX + "$Wrap");
+-            provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, PREFIX + "$Wrap");
+-            provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
++            // BEGIN android-changed
++            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
++            // END android-changed
++            // BEGIN android-removed
++            // provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
++            // END android-removed
+ 
+             if (provider.hasAlgorithm("MessageDigest", "SHA-1"))
+             {
+                 provider.addAlgorithm("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3Key");
+-                provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES3Key");
+-                provider.addAlgorithm("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$OldPBEWithSHAAndDES3Key");
++                // BEGIN android-removed
++                // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES3Key");
++                // provider.addAlgorithm("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$OldPBEWithSHAAndDES3Key");
++                // END android-removed
+                 provider.addAlgorithm("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2Key");
+-                provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES2Key");
++                // BEGIN android-removed
++                // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES2Key");
++                // END android-removed
+                 provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                 provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+@@ -357,31 +387,37 @@
+             }
+ 
+             provider.addAlgorithm("KeyGenerator.DESEDE", PREFIX + "$KeyGenerator");
+-            provider.addAlgorithm("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$KeyGenerator3");
+-            provider.addAlgorithm("KeyGenerator.DESEDEWRAP", PREFIX + "$KeyGenerator");
++            // BEGIN android-removed
++            // provider.addAlgorithm("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$KeyGenerator3");
++            // provider.addAlgorithm("KeyGenerator.DESEDEWRAP", PREFIX + "$KeyGenerator");
++            // END android-removed
+ 
+             provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory");
+ 
+-            provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
+-            provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+-
+-            provider.addAlgorithm("Mac.DESEDEMAC/CFB8", PREFIX + "$DESedeCFB8");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+-
+-            provider.addAlgorithm("Mac.DESEDEMAC64", PREFIX + "$DESede64");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+-
+-            provider.addAlgorithm("Mac.DESEDEMAC64WITHISO7816-4PADDING", PREFIX + "$DESede64with7816d4");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+-            provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
++            // provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
++            //
++            // provider.addAlgorithm("Mac.DESEDEMAC/CFB8", PREFIX + "$DESedeCFB8");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
++            //
++            // provider.addAlgorithm("Mac.DESEDEMAC64", PREFIX + "$DESede64");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
++            //
++            // provider.addAlgorithm("Mac.DESEDEMAC64WITHISO7816-4PADDING", PREFIX + "$DESede64with7816d4");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // END android-removed
+ 
+             provider.addAlgorithm("AlgorithmParameters.DESEDE", PACKAGE + ".util.IvAlgorithmParameters");
+             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+ 
+-            provider.addAlgorithm("AlgorithmParameterGenerator.DESEDE",  PREFIX + "$AlgParamGen");
+-            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
++            // BEGIN android-removed
++            // provider.addAlgorithm("AlgorithmParameterGenerator.DESEDE",  PREFIX + "$AlgParamGen");
++            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
++            // END android-removed
+         }
+     }
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java	2012-09-11 00:12:44.000000000 +0000
+@@ -7,13 +7,17 @@
+ 
+ import javax.crypto.spec.IvParameterSpec;
+ import javax.crypto.spec.PBEParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.RC2ParameterSpec;
++// END android-removed
+ 
+ import org.bouncycastle.asn1.ASN1Encoding;
+ import org.bouncycastle.asn1.ASN1Primitive;
+ import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+ import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+-import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
++// END android-removed
+ import org.bouncycastle.util.Arrays;
+ 
+ public abstract class BaseAlgorithmParameters
+@@ -39,177 +43,179 @@
+     protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+         throws InvalidParameterSpecException;
+ 
+-    public static class RC2AlgorithmParameters
+-        extends BaseAlgorithmParameters
+-    {
+-        private static final short[] table = {
+-           0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+-           0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+-           0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+-           0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+-           0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+-           0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+-           0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+-           0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+-           0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+-           0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+-           0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+-           0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+-           0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+-           0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+-           0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+-           0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+-        };
+-
+-        private static final short[] ekb = {
+-           0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+-           0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+-           0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+-           0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+-           0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+-           0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+-           0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+-           0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+-           0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+-           0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+-           0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+-           0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+-           0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+-           0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+-           0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+-           0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+-        };
+-
+-        private byte[]  iv;
+-        private int     parameterVersion = 58;
+-
+-        protected byte[] engineGetEncoded() 
+-        {
+-            return Arrays.clone(iv);
+-        }
+-
+-        protected byte[] engineGetEncoded(
+-            String format) 
+-            throws IOException
+-        {
+-            if (this.isASN1FormatString(format))
+-            {
+-                if (parameterVersion == -1)
+-                {
+-                    return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+-                }
+-                else
+-                {
+-                    return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+-                }
+-            }
+-
+-            if (format.equals("RAW"))
+-            {
+-                return engineGetEncoded();
+-            }
+-
+-            return null;
+-        }
+-
+-        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+-            Class paramSpec) 
+-            throws InvalidParameterSpecException
+-        {
+-            if (paramSpec == RC2ParameterSpec.class)
+-            {
+-                if (parameterVersion != -1)
+-                {
+-                    if (parameterVersion < 256)
+-                    {
+-                        return new RC2ParameterSpec(ekb[parameterVersion], iv);
+-                    }
+-                    else
+-                    {
+-                        return new RC2ParameterSpec(parameterVersion, iv);
+-                    }
+-                }
+-            }
+-
+-            if (paramSpec == IvParameterSpec.class)
+-            {
+-                return new IvParameterSpec(iv);
+-            }
+-
+-            throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+-        }
+-
+-        protected void engineInit(
+-            AlgorithmParameterSpec paramSpec) 
+-            throws InvalidParameterSpecException
+-        {
+-            if (paramSpec instanceof IvParameterSpec)
+-            {
+-                this.iv = ((IvParameterSpec)paramSpec).getIV();
+-            }
+-            else if (paramSpec instanceof RC2ParameterSpec)
+-            {
+-                int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+-                if (effKeyBits != -1)
+-                {
+-                    if (effKeyBits < 256)
+-                    {
+-                        parameterVersion = table[effKeyBits];
+-                    }
+-                    else
+-                    {
+-                        parameterVersion = effKeyBits;
+-                    }
+-                }
+-
+-                this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+-            }
+-            else
+-            {
+-                throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+-            }
+-        }
+-
+-        protected void engineInit(
+-            byte[] params) 
+-            throws IOException
+-        {
+-            this.iv = Arrays.clone(params);
+-        }
+-
+-        protected void engineInit(
+-            byte[] params,
+-            String format) 
+-            throws IOException
+-        {
+-            if (this.isASN1FormatString(format))
+-            {
+-                RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Primitive.fromByteArray(params));
+-
+-                if (p.getRC2ParameterVersion() != null)
+-                {
+-                    parameterVersion = p.getRC2ParameterVersion().intValue();
+-                }
+-
+-                iv = p.getIV();
+-
+-                return;
+-            }
+-
+-            if (format.equals("RAW"))
+-            {
+-                engineInit(params);
+-                return;
+-            }
+-
+-            throw new IOException("Unknown parameters format in IV parameters object");
+-        }
+-
+-        protected String engineToString() 
+-        {
+-            return "RC2 Parameters";
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class RC2AlgorithmParameters
++    //     extends BaseAlgorithmParameters
++    // {
++    //     private static final short[] table = {
++    //        0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
++    //        0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
++    //        0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
++    //        0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
++    //        0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
++    //        0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
++    //        0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
++    //        0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
++    //        0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
++    //        0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
++    //        0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
++    //        0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
++    //        0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
++    //        0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
++    //        0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
++    //        0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
++    //     };
++    //
++    //     private static final short[] ekb = {
++    //        0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
++    //        0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
++    //        0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
++    //        0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
++    //        0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
++    //        0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
++    //        0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
++    //        0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
++    //        0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
++    //        0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
++    //        0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
++    //        0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
++    //        0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
++    //        0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
++    //        0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
++    //        0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
++    //     };
++    //
++    //     private byte[]  iv;
++    //     private int     parameterVersion = 58;
++    //
++    //     protected byte[] engineGetEncoded() 
++    //     {
++    //         return Arrays.clone(iv);
++    //     }
++    //
++    //     protected byte[] engineGetEncoded(
++    //         String format) 
++    //         throws IOException
++    //     {
++    //         if (this.isASN1FormatString(format))
++    //         {
++    //             if (parameterVersion == -1)
++    //             {
++    //                 return new RC2CBCParameter(engineGetEncoded()).getEncoded();
++    //             }
++    //             else
++    //             {
++    //                 return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
++    //             }
++    //         }
++    //
++    //         if (format.equals("RAW"))
++    //         {
++    //             return engineGetEncoded();
++    //         }
++    //
++    //         return null;
++    //     }
++    //
++    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
++    //         Class paramSpec) 
++    //         throws InvalidParameterSpecException
++    //     {
++    //         if (paramSpec == RC2ParameterSpec.class)
++    //         {
++    //             if (parameterVersion != -1)
++    //             {
++    //                 if (parameterVersion < 256)
++    //                 {
++    //                     return new RC2ParameterSpec(ekb[parameterVersion], iv);
++    //                 }
++    //                 else
++    //                 {
++    //                     return new RC2ParameterSpec(parameterVersion, iv);
++    //                 }
++    //             }
++    //         }
++    //
++    //         if (paramSpec == IvParameterSpec.class)
++    //         {
++    //             return new IvParameterSpec(iv);
++    //         }
++    //
++    //         throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
++    //     }
++    //
++    //     protected void engineInit(
++    //         AlgorithmParameterSpec paramSpec) 
++    //         throws InvalidParameterSpecException
++    //     {
++    //         if (paramSpec instanceof IvParameterSpec)
++    //         {
++    //             this.iv = ((IvParameterSpec)paramSpec).getIV();
++    //         }
++    //         else if (paramSpec instanceof RC2ParameterSpec)
++    //         {
++    //             int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
++    //             if (effKeyBits != -1)
++    //             {
++    //                 if (effKeyBits < 256)
++    //                 {
++    //                     parameterVersion = table[effKeyBits];
++    //                 }
++    //                 else
++    //                 {
++    //                     parameterVersion = effKeyBits;
++    //                 }
++    //             }
++    //
++    //             this.iv = ((RC2ParameterSpec)paramSpec).getIV();
++    //         }
++    //         else
++    //         {
++    //             throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
++    //         }
++    //     }
++    //
++    //     protected void engineInit(
++    //         byte[] params) 
++    //         throws IOException
++    //     {
++    //         this.iv = Arrays.clone(params);
++    //     }
++    //
++    //     protected void engineInit(
++    //         byte[] params,
++    //         String format) 
++    //         throws IOException
++    //     {
++    //         if (this.isASN1FormatString(format))
++    //         {
++    //             RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Primitive.fromByteArray(params));
++    //
++    //             if (p.getRC2ParameterVersion() != null)
++    //             {
++    //                 parameterVersion = p.getRC2ParameterVersion().intValue();
++    //             }
++    //
++    //             iv = p.getIV();
++    //
++    //             return;
++    //         }
++    //
++    //         if (format.equals("RAW"))
++    //         {
++    //             engineInit(params);
++    //             return;
++    //         }
++    //
++    //         throw new IOException("Unknown parameters format in IV parameters object");
++    //     }
++    //
++    //     protected String engineToString() 
++    //     {
++    //         return "RC2 Parameters";
++    //     }
++    // }
++    // END android-removed
+ 
+     public static class PBKDF2
+         extends BaseAlgorithmParameters
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java	2012-09-11 00:12:44.000000000 +0000
+@@ -17,8 +17,10 @@
+ import javax.crypto.ShortBufferException;
+ import javax.crypto.spec.IvParameterSpec;
+ import javax.crypto.spec.PBEParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
+-import javax.crypto.spec.RC5ParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.RC2ParameterSpec;
++// import javax.crypto.spec.RC5ParameterSpec;
++// END android-removed
+ 
+ import org.bouncycastle.crypto.BufferedBlockCipher;
+ import org.bouncycastle.crypto.CipherParameters;
+@@ -29,12 +31,18 @@
+ import org.bouncycastle.crypto.modes.CCMBlockCipher;
+ import org.bouncycastle.crypto.modes.CFBBlockCipher;
+ import org.bouncycastle.crypto.modes.CTSBlockCipher;
+-import org.bouncycastle.crypto.modes.EAXBlockCipher;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.modes.EAXBlockCipher;
++// END android-removed
+ import org.bouncycastle.crypto.modes.GCMBlockCipher;
+-import org.bouncycastle.crypto.modes.GOFBBlockCipher;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
++// END android-removed
+ import org.bouncycastle.crypto.modes.OFBBlockCipher;
+-import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+-import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
++// import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
++// END android-removed
+ import org.bouncycastle.crypto.modes.SICBlockCipher;
+ import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+ import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+@@ -46,11 +54,17 @@
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+ import org.bouncycastle.crypto.params.ParametersWithRandom;
+-import org.bouncycastle.crypto.params.ParametersWithSBox;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.params.ParametersWithSBox;
++// END android-removed
+ import org.bouncycastle.crypto.params.RC2Parameters;
+-import org.bouncycastle.crypto.params.RC5Parameters;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.params.RC5Parameters;
++// 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;
+ 
+@@ -63,11 +77,15 @@
+     //
+     private Class[]                 availableSpecs =
+                                     {
+-                                        RC2ParameterSpec.class,
+-                                        RC5ParameterSpec.class,
++                                        // BEGIN android-removed
++                                        // RC2ParameterSpec.class,
++                                        // RC5ParameterSpec.class,
++                                        // END android-removed
+                                         IvParameterSpec.class,
+                                         PBEParameterSpec.class,
+-                                        GOST28147ParameterSpec.class
++                                        // BEGIN android-removed
++                                        // GOST28147ParameterSpec.class
++                                        // END android-removed
+                                     };
+ 
+     private org.bouncycastle.crypto.BlockCipher baseEngine;
+@@ -222,20 +240,22 @@
+                         new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+             }
+         }
+-        else if (modeName.startsWith("PGP"))
+-        {
+-            boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+-
+-            ivLength = baseEngine.getBlockSize();
+-            cipher = new BufferedGenericBlockCipher(
+-                new PGPCFBBlockCipher(baseEngine, inlineIV));
+-        }
+-        else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+-        {
+-            ivLength = 0;
+-            cipher = new BufferedGenericBlockCipher(
+-                new OpenPGPCFBBlockCipher(baseEngine));
+-        }
++        // BEGIN android-removed
++        // else if (modeName.startsWith("PGP"))
++        // {
++        //     boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
++
++        //     ivLength = baseEngine.getBlockSize();
++        //     cipher = new BufferedGenericBlockCipher(
++        //         new PGPCFBBlockCipher(baseEngine, inlineIV));
++        // }
++        // else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
++        // {
++        //     ivLength = 0;
++        //     cipher = new BufferedGenericBlockCipher(
++        //         new OpenPGPCFBBlockCipher(baseEngine));
++        // }
++        // END android-removed
+         else if (modeName.startsWith("SIC"))
+         {
+             ivLength = baseEngine.getBlockSize();
+@@ -252,12 +272,14 @@
+             cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                         new SICBlockCipher(baseEngine)));
+         }
+-        else if (modeName.startsWith("GOFB"))
+-        {
+-            ivLength = baseEngine.getBlockSize();
+-            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+-                        new GOFBBlockCipher(baseEngine)));
+-        }
++        // BEGIN android-removed
++        // else if (modeName.startsWith("GOFB"))
++        // {
++        //     ivLength = baseEngine.getBlockSize();
++        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
++        //                 new GOFBBlockCipher(baseEngine)));
++        // }
++        // END android-removed
+         else if (modeName.startsWith("CTS"))
+         {
+             ivLength = baseEngine.getBlockSize();
+@@ -268,11 +290,13 @@
+             ivLength = baseEngine.getBlockSize();
+             cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+         }
+-        else if (modeName.startsWith("EAX"))
+-        {
+-            ivLength = baseEngine.getBlockSize();
+-            cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+-        }
++        // BEGIN android-removed
++        // else if (modeName.startsWith("EAX"))
++        // {
++        //     ivLength = baseEngine.getBlockSize();
++        //     cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
++        // }
++        // END android-removed
+         else if (modeName.startsWith("GCM"))
+         {
+             ivLength = baseEngine.getBlockSize();
+@@ -441,63 +465,65 @@
+                 param = new KeyParameter(key.getEncoded());
+             }
+         }
+-        else if (params instanceof GOST28147ParameterSpec)
+-        {
+-            GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
+-
+-            param = new ParametersWithSBox(
+-                       new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+-
+-            if (gost28147Param.getIV() != null && ivLength != 0)
+-            {
+-                param = new ParametersWithIV(param, gost28147Param.getIV());
+-                ivParam = (ParametersWithIV)param;
+-            }
+-        }
+-        else if (params instanceof RC2ParameterSpec)
+-        {
+-            RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
+-
+-            param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+-
+-            if (rc2Param.getIV() != null && ivLength != 0)
+-            {
+-                param = new ParametersWithIV(param, rc2Param.getIV());
+-                ivParam = (ParametersWithIV)param;
+-            }
+-        }
+-        else if (params instanceof RC5ParameterSpec)
+-        {
+-            RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
+-
+-            param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+-            if (baseEngine.getAlgorithmName().startsWith("RC5"))
+-            {
+-                if (baseEngine.getAlgorithmName().equals("RC5-32"))
+-                {
+-                    if (rc5Param.getWordSize() != 32)
+-                    {
+-                        throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+-                    }
+-                }
+-                else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+-                {
+-                    if (rc5Param.getWordSize() != 64)
+-                    {
+-                        throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+-                    }
+-                }
+-            }
+-            else
+-            {
+-                throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+-            }
+-            if ((rc5Param.getIV() != null) && (ivLength != 0))
+-            {
+-                param = new ParametersWithIV(param, rc5Param.getIV());
+-                ivParam = (ParametersWithIV)param;
+-            }
+-        }
++        // BEGIN android-removed
++        // else if (params instanceof GOST28147ParameterSpec)
++        // {
++        //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
++        //
++        //     param = new ParametersWithSBox(
++        //                new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
++        //
++        //     if (gost28147Param.getIV() != null && ivLength != 0)
++        //     {
++        //         param = new ParametersWithIV(param, gost28147Param.getIV());
++        //         ivParam = (ParametersWithIV)param;
++        //     }
++        // }
++        // else if (params instanceof RC2ParameterSpec)
++        // {
++        //     RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
++        //
++        //     param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
++        //
++        //     if (rc2Param.getIV() != null && ivLength != 0)
++        //     {
++        //         param = new ParametersWithIV(param, rc2Param.getIV());
++        //         ivParam = (ParametersWithIV)param;
++        //     }
++        // }
++        // else if (params instanceof RC5ParameterSpec)
++        // {
++        //     RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
++        //
++        //     param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
++        //     if (baseEngine.getAlgorithmName().startsWith("RC5"))
++        //     {
++        //         if (baseEngine.getAlgorithmName().equals("RC5-32"))
++        //         {
++        //             if (rc5Param.getWordSize() != 32)
++        //             {
++        //                 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
++        //             }
++        //         }
++        //         else if (baseEngine.getAlgorithmName().equals("RC5-64"))
++        //         {
++        //             if (rc5Param.getWordSize() != 64)
++        //             {
++        //                 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
++        //             }
++        //         }
++        //     }
++        //     else
++        //     {
++        //         throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
++        //     }
++        //     if ((rc5Param.getIV() != null) && (ivLength != 0))
++        //     {
++        //         param = new ParametersWithIV(param, rc5Param.getIV());
++        //         ivParam = (ParametersWithIV)param;
++        //     }
++        // }
++        // END android-removed
+         else
+         {
+             throw new InvalidAlgorithmParameterException("unknown parameter type.");
+@@ -701,10 +727,20 @@
+         int     inputLen,
+         byte[]  output,
+         int     outputOffset) 
+-        throws IllegalBlockSizeException, BadPaddingException
++        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+     {
++        // BEGIN android-note
++        // added ShortBufferException to the throws statement
++        // END android-note
+         int     len = 0;
+ 
++        // BEGIN android-added
++        int outputLen = cipher.getOutputSize(inputLen);
++
++        if (outputLen + outputOffset > output.length) {
++            throw new ShortBufferException("need at least " + outputLen + " bytes");
++        }
++        // BEGIN android-added
+         if (inputLen != 0)
+         {
+                 len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java	2012-09-11 00:12:44.000000000 +0000
+@@ -56,6 +56,11 @@
+     {
+         try
+         {
++            // BEGIN android-added
++            if (random == null) {
++                random = new SecureRandom();
++            }
++            // END android-added
+             engine.init(new KeyGenerationParameters(random, keySize));
+             uninitialised = false;
+         }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java	2012-09-11 00:12:44.000000000 +0000
+@@ -11,25 +11,34 @@
+ 
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.Mac;
+-import org.bouncycastle.crypto.digests.MD2Digest;
+-import org.bouncycastle.crypto.digests.MD4Digest;
+-import org.bouncycastle.crypto.digests.MD5Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.SHA384Digest;
+-import org.bouncycastle.crypto.digests.SHA512Digest;
+-import org.bouncycastle.crypto.digests.TigerDigest;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.MD2Digest;
++// import org.bouncycastle.crypto.digests.MD4Digest;
++// import org.bouncycastle.crypto.digests.MD5Digest;
++// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
++// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
++// import org.bouncycastle.crypto.digests.SHA1Digest;
++// import org.bouncycastle.crypto.digests.SHA224Digest;
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.SHA384Digest;
++// import org.bouncycastle.crypto.digests.SHA512Digest;
++// import org.bouncycastle.crypto.digests.TigerDigest;
++// END android-removed
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
+ import org.bouncycastle.crypto.engines.DESEngine;
+ import org.bouncycastle.crypto.engines.RC2Engine;
+ import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+-import org.bouncycastle.crypto.macs.GOST28147Mac;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
++// import org.bouncycastle.crypto.macs.GOST28147Mac;
++// END android-removed
+ import org.bouncycastle.crypto.macs.HMac;
+-import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
+-import org.bouncycastle.crypto.macs.OldHMac;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
++// import org.bouncycastle.crypto.macs.OldHMac;
++// END android-removed
+ import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+@@ -179,91 +188,93 @@
+         }
+     }
+ 
+-    /**
+-     * GOST28147
+-     */
+-    public static class GOST28147
+-        extends BaseMac
+-    {
+-        public GOST28147()
+-        {
+-            super(new GOST28147Mac());
+-        }
+-    }
+-
+-    
+-
+-    /**
+-     * DES
+-     */
+-    public static class DESCFB8
+-        extends BaseMac
+-    {
+-        public DESCFB8()
+-        {
+-            super(new CFBBlockCipherMac(new DESEngine()));
+-        }
+-    }
+-
+-    /**
+-     * RC2CFB8
+-     */
+-    public static class RC2CFB8
+-        extends BaseMac
+-    {
+-        public RC2CFB8()
+-        {
+-            super(new CFBBlockCipherMac(new RC2Engine()));
+-        }
+-    }
+-
+-    /**
+-     * DES9797Alg3with7816-4Padding
+-     */
+-    public static class DES9797Alg3with7816d4
+-        extends BaseMac
+-    {
+-        public DES9797Alg3with7816d4()
+-        {
+-            super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
+-        }
+-    }
+-
+-    /**
+-     * DES9797Alg3
+-     */
+-    public static class DES9797Alg3
+-        extends BaseMac
+-    {
+-        public DES9797Alg3()
+-        {
+-            super(new ISO9797Alg3Mac(new DESEngine()));
+-        }
+-    }
+-
+-    /**
+-     * MD2 HMac
+-     */
+-    public static class MD2
+-        extends BaseMac
+-    {
+-        public MD2()
+-        {
+-            super(new HMac(new MD2Digest()));
+-        }
+-    }
+-
+-    /**
+-     * MD4 HMac
+-     */
+-    public static class MD4
+-        extends BaseMac
+-    {
+-        public MD4()
+-        {
+-            super(new HMac(new MD4Digest()));
+-        }
+-    }
++    // BEGIN android-removed
++    // /**
++    //  * GOST28147
++    //  */
++    // public static class GOST28147
++    //     extends BaseMac
++    // {
++    //     public GOST28147()
++    //     {
++    //         super(new GOST28147Mac());
++    //     }
++    // }
++    //
++    //
++    //
++    // /**
++    //  * DES
++    //  */
++    // public static class DESCFB8
++    //     extends BaseMac
++    // {
++    //     public DESCFB8()
++    //     {
++    //         super(new CFBBlockCipherMac(new DESEngine()));
++    //     }
++    // }
++    //
++    // /**
++    //  * RC2CFB8
++    //  */
++    // public static class RC2CFB8
++    //     extends BaseMac
++    // {
++    //     public RC2CFB8()
++    //     {
++    //         super(new CFBBlockCipherMac(new RC2Engine()));
++    //     }
++    // }
++    //
++    // /**
++    //  * DES9797Alg3with7816-4Padding
++    //  */
++    // public static class DES9797Alg3with7816d4
++    //     extends BaseMac
++    // {
++    //     public DES9797Alg3with7816d4()
++    //     {
++    //         super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
++    //     }
++    // }
++    //
++    // /**
++    //  * DES9797Alg3
++    //  */
++    // public static class DES9797Alg3
++    //     extends BaseMac
++    // {
++    //     public DES9797Alg3()
++    //     {
++    //         super(new ISO9797Alg3Mac(new DESEngine()));
++    //     }
++    // }
++    //
++    // /**
++    //  * MD2 HMac
++    //  */
++    // public static class MD2
++    //     extends BaseMac
++    // {
++    //     public MD2()
++    //     {
++    //         super(new HMac(new MD2Digest()));
++    //     }
++    // }
++    //
++    // /**
++    //  * MD4 HMac
++    //  */
++    // public static class MD4
++    //     extends BaseMac
++    // {
++    //     public MD4()
++    //     {
++    //         super(new HMac(new MD4Digest()));
++    //     }
++    // }
++    // END android-removed
+ 
+     /**
+      * MD5 HMac
+@@ -273,7 +284,9 @@
+     {
+         public MD5()
+         {
+-            super(new HMac(new MD5Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.MD5()));
++            // END android-changed
+         }
+     }
+ 
+@@ -285,21 +298,25 @@
+     {
+         public SHA1()
+         {
+-            super(new HMac(new SHA1Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA1()));
++            // END android-changed
+         }
+     }
+ 
+-    /**
+-     * SHA-224 HMac
+-     */
+-    public static class SHA224
+-        extends BaseMac
+-    {
+-        public SHA224()
+-        {
+-            super(new HMac(new SHA224Digest()));
+-        }
+-    }
++    // BEGIN android-removed
++    // /**
++    //  * SHA-224 HMac
++    //  */
++    // public static class SHA224
++    //     extends BaseMac
++    // {
++    //     public SHA224()
++    //     {
++    //         super(new HMac(new SHA224Digest()));
++    //     }
++    // }
++    // END android-removed
+     
+     /**
+      * SHA-256 HMac
+@@ -309,7 +326,7 @@
+     {
+         public SHA256()
+         {
+-            super(new HMac(new SHA256Digest()));
++            super(new HMac(new OpenSSLDigest.SHA256()));
+         }
+     }
+ 
+@@ -321,18 +338,20 @@
+     {
+         public SHA384()
+         {
+-            super(new HMac(new SHA384Digest()));
++            super(new HMac(new OpenSSLDigest.SHA384()));
+         }
+     }
+ 
+-    public static class OldSHA384
+-        extends BaseMac
+-    {
+-        public OldSHA384()
+-        {
+-            super(new OldHMac(new SHA384Digest()));
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class OldSHA384
++    //     extends BaseMac
++    // {
++    //     public OldSHA384()
++    //     {
++    //         super(new OldHMac(new SHA384Digest()));
++    //     }
++    // }
++    // END android-removed
+     
+     /**
+      * SHA-512 HMac
+@@ -342,75 +361,77 @@
+     {
+         public SHA512()
+         {
+-            super(new HMac(new SHA512Digest()));
+-        }
+-    }
+-
+-    /**
+-     * SHA-512 HMac
+-     */
+-    public static class OldSHA512
+-        extends BaseMac
+-    {
+-        public OldSHA512()
+-        {
+-            super(new OldHMac(new SHA512Digest()));
+-        }
+-    }
+-    
+-    /**
+-     * RIPEMD128 HMac
+-     */
+-    public static class RIPEMD128
+-        extends BaseMac
+-    {
+-        public RIPEMD128()
+-        {
+-            super(new HMac(new RIPEMD128Digest()));
+-        }
+-    }
+-
+-    /**
+-     * RIPEMD160 HMac
+-     */
+-    public static class RIPEMD160
+-        extends BaseMac
+-    {
+-        public RIPEMD160()
+-        {
+-            super(new HMac(new RIPEMD160Digest()));
+-        }
+-    }
+-
+-    /**
+-     * Tiger HMac
+-     */
+-    public static class Tiger
+-        extends BaseMac
+-    {
+-        public Tiger()
+-        {
+-            super(new HMac(new TigerDigest()));
++            super(new HMac(new OpenSSLDigest.SHA512()));
+         }
+     }
+ 
++    // BEGIN android-removed
++    // /**
++    //  * SHA-512 HMac
++    //  */
++    // public static class OldSHA512
++    //     extends BaseMac
++    // {
++    //     public OldSHA512()
++    //     {
++    //         super(new OldHMac(new SHA512Digest()));
++    //     }
++    // }
++    //    
++    // /**
++    //  * RIPEMD128 HMac
++    //  */
++    // public static class RIPEMD128
++    //     extends BaseMac
++    // {
++    //     public RIPEMD128()
++    //     {
++    //         super(new HMac(new RIPEMD128Digest()));
++    //     }
++    // }
+     //
+-    // PKCS12 states that the same algorithm should be used
+-    // for the key generation as is used in the HMAC, so that
+-    // is what we do here.
++    // /**
++    //  * RIPEMD160 HMac
++    //  */
++    // public static class RIPEMD160
++    //     extends BaseMac
++    // {
++    //     public RIPEMD160()
++    //     {
++    //         super(new HMac(new RIPEMD160Digest()));
++    //     }
++    // }
+     //
+-
+-    /**
+-     * PBEWithHmacRIPEMD160
+-     */
+-    public static class PBEWithRIPEMD160
+-        extends BaseMac
+-    {
+-        public PBEWithRIPEMD160()
+-        {
+-            super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
+-        }
+-    }
++    // /**
++    //  * Tiger HMac
++    //  */
++    // public static class Tiger
++    //     extends BaseMac
++    // {
++    //     public Tiger()
++    //     {
++    //         super(new HMac(new TigerDigest()));
++    //     }
++    // }
++    //
++    // //
++    // // PKCS12 states that the same algorithm should be used
++    // // for the key generation as is used in the HMAC, so that
++    // // is what we do here.
++    // //
++    //
++    // /**
++    //  * PBEWithHmacRIPEMD160
++    //  */
++    // public static class PBEWithRIPEMD160
++    //     extends BaseMac
++    // {
++    //     public PBEWithRIPEMD160()
++    //     {
++    //         super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
++    //     }
++    // }
++    // END android-removed
+ 
+     /**
+      * PBEWithHmacSHA
+@@ -420,19 +441,23 @@
+     {
+         public PBEWithSHA()
+         {
+-            super(new HMac(new SHA1Digest()), PKCS12, SHA1, 160);
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA1()), PKCS12, SHA1, 160);
++            // END android-changed
+         }
+     }
+ 
+-    /**
+-     * PBEWithHmacTiger
+-     */
+-    public static class PBEWithTiger
+-        extends BaseMac
+-    {
+-        public PBEWithTiger()
+-        {
+-            super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
+-        }
+-    }
++    // BEGIN android-removed
++    // /**
++    //  * PBEWithHmacTiger
++    //  */
++    // public static class PBEWithTiger
++    //     extends BaseMac
++    // {
++    //     public PBEWithTiger()
++    //     {
++    //         super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
++    //     }
++    // }
++    // END android-removed
+ }
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java	2012-09-11 00:12:44.000000000 +0000
+@@ -13,8 +13,10 @@
+ import javax.crypto.ShortBufferException;
+ import javax.crypto.spec.IvParameterSpec;
+ import javax.crypto.spec.PBEParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
+-import javax.crypto.spec.RC5ParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.RC2ParameterSpec;
++// import javax.crypto.spec.RC5ParameterSpec;
++// END android-removed
+ 
+ import org.bouncycastle.crypto.BlockCipher;
+ import org.bouncycastle.crypto.CipherParameters;
+@@ -34,8 +36,10 @@
+     //
+     private Class[]                 availableSpecs =
+                                     {
+-                                        RC2ParameterSpec.class,
+-                                        RC5ParameterSpec.class,
++                                        // BEGIN android-removed
++                                        // RC2ParameterSpec.class,
++                                        // RC5ParameterSpec.class,
++                                        // END android-removed
+                                         IvParameterSpec.class,
+                                         PBEParameterSpec.class
+                                     };
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java	2012-09-11 00:12:44.000000000 +0000
+@@ -22,8 +22,10 @@
+ import javax.crypto.ShortBufferException;
+ import javax.crypto.spec.IvParameterSpec;
+ import javax.crypto.spec.PBEParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
+-import javax.crypto.spec.RC5ParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.RC2ParameterSpec;
++// import javax.crypto.spec.RC5ParameterSpec;
++// END android-removed
+ import javax.crypto.spec.SecretKeySpec;
+ 
+ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+@@ -45,8 +47,10 @@
+                                     {
+                                         IvParameterSpec.class,
+                                         PBEParameterSpec.class,
+-                                        RC2ParameterSpec.class,
+-                                        RC5ParameterSpec.class
++                                        // BEGIN android-removed
++                                        // RC2ParameterSpec.class,
++                                        // RC5ParameterSpec.class
++                                        // END android-removed
+                                     };
+ 
+     protected int                     pbeType = PKCS12;
+@@ -258,16 +262,19 @@
+         return null;
+     }
+ 
++    // BEGIN android-changed
++    // added ShortBufferException to throws statement
+     protected int engineDoFinal(
+         byte[]  input,
+         int     inputOffset,
+         int     inputLen,
+         byte[]  output,
+         int     outputOffset)
+-        throws IllegalBlockSizeException, BadPaddingException
++        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+     {
+         return 0;
+     }
++    // END android-changed
+ 
+     protected byte[] engineWrap(
+         Key     key)
+@@ -300,7 +307,12 @@
+         byte[]  wrappedKey,
+         String  wrappedKeyAlgorithm,
+         int     wrappedKeyType)
+-    throws InvalidKeyException
++    // BEGIN android-removed
++    // throws InvalidKeyException
++    // END android-removed
++    // BEGIN android-added
++    throws InvalidKeyException, NoSuchAlgorithmException
++    // END android-added
+     {
+         byte[] encoded;
+         try
+@@ -376,10 +388,12 @@
+             {
+                 throw new InvalidKeyException("Unknown key type " + e.getMessage());
+             }
+-            catch (NoSuchAlgorithmException e)
+-            {
+-                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+-            }
++            // BEGIN android-removed
++            // catch (NoSuchAlgorithmException e)
++            // {
++            //     throw new InvalidKeyException("Unknown key type " + e.getMessage());
++            // }
++            // END android-removed
+             catch (InvalidKeySpecException e2)
+             {
+                 throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java	2012-09-11 00:12:44.000000000 +0000
+@@ -7,12 +7,17 @@
+ 
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.PBEParametersGenerator;
+-import org.bouncycastle.crypto.digests.MD2Digest;
+-import org.bouncycastle.crypto.digests.MD5Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.TigerDigest;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.MD2Digest;
++// import org.bouncycastle.crypto.digests.MD5Digest;
++// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
++// import org.bouncycastle.crypto.digests.SHA1Digest;
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.TigerDigest;
++// END android-removed
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
+ import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+ import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+ import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
+@@ -28,10 +33,14 @@
+     //
+     static final int        MD5         = 0;
+     static final int        SHA1        = 1;
+-    static final int        RIPEMD160   = 2;
+-    static final int        TIGER       = 3;
++    // BEGIN android-removed
++    // static final int        RIPEMD160   = 2;
++    // static final int        TIGER       = 3;
++    // END android-removed
+     static final int        SHA256      = 4;
+-    static final int        MD2         = 5;
++    // BEGIN android-removed
++    // static final int        MD2         = 5;
++    // END android-removed
+ 
+     static final int        PKCS5S1     = 0;
+     static final int        PKCS5S2     = 1;
+@@ -53,14 +62,20 @@
+             {
+                 switch (hash)
+                 {
+-                case MD2:
+-                    generator = new PKCS5S1ParametersGenerator(new MD2Digest());
+-                    break;
++                // BEGIN android-removed
++                // case MD2:
++                //     generator = new PKCS5S1ParametersGenerator(new MD2Digest());
++                //     break;
++                // END android-removed
+                 case MD5:
+-                    generator = new PKCS5S1ParametersGenerator(new MD5Digest());
++                    // BEGIN android-changed
++                    generator = new PKCS5S1ParametersGenerator(new OpenSSLDigest.MD5());
++                    // END android-changed
+                     break;
+                 case SHA1:
+-                    generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
++                    // BEGIN android-changed
++                    generator = new PKCS5S1ParametersGenerator(new OpenSSLDigest.SHA1());
++                    // END android-changed
+                     break;
+                 default:
+                     throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
+@@ -74,23 +89,33 @@
+             {
+                 switch (hash)
+                 {
+-                case MD2:
+-                    generator = new PKCS12ParametersGenerator(new MD2Digest());
+-                    break;
++                // BEGIN android-removed
++                // case MD2:
++                //     generator = new PKCS12ParametersGenerator(new MD2Digest());
++                //     break;
++                // END android-removed
+                 case MD5:
+-                    generator = new PKCS12ParametersGenerator(new MD5Digest());
++                    // BEGIN android-changed
++                    generator = new PKCS12ParametersGenerator(new OpenSSLDigest.MD5());
++                    // END android-changed
+                     break;
+                 case SHA1:
+-                    generator = new PKCS12ParametersGenerator(new SHA1Digest());
+-                    break;
+-                case RIPEMD160:
+-                    generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+-                    break;
+-                case TIGER:
+-                    generator = new PKCS12ParametersGenerator(new TigerDigest());
++                    // BEGIN android-changed
++                    generator = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
++                    // END android-changed
+                     break;
++                // BEGIN android-removed
++                // case RIPEMD160:
++                //     generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
++                //     break;
++                // case TIGER:
++                //     generator = new PKCS12ParametersGenerator(new TigerDigest());
++                //     break;
++                // END android-removed
+                 case SHA256:
+-                    generator = new PKCS12ParametersGenerator(new SHA256Digest());
++                    // BEGIN android-changed
++                    generator = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA256());
++                    // END android-changed
+                     break;
+                 default:
+                     throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/util/DigestFactory.java bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/util/DigestFactory.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jcajce/provider/util/DigestFactory.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jcajce/provider/util/DigestFactory.java	2012-09-11 00:12:44.000000000 +0000
+@@ -10,19 +10,26 @@
+ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+ import org.bouncycastle.crypto.Digest;
+-import org.bouncycastle.crypto.digests.MD5Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.SHA384Digest;
+-import org.bouncycastle.crypto.digests.SHA512Digest;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.MD5Digest;
++// import org.bouncycastle.crypto.digests.SHA1Digest;
++// import org.bouncycastle.crypto.digests.SHA224Digest;
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.SHA384Digest;
++// import org.bouncycastle.crypto.digests.SHA512Digest;
++// END android-removed
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
+ 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 @@
+         
+         if (sha1.contains(digestName))
+         {
+-            return new SHA1Digest();
++            // BEGIN android-changed
++            return new OpenSSLDigest.SHA1();
++            // END android-changed
+         }
+         if (md5.contains(digestName))
+         {
+-            return new MD5Digest();
+-        }
+-        if (sha224.contains(digestName))
+-        {
+-            return new SHA224Digest();
+-        }
++            // BEGIN android-changed
++            return new OpenSSLDigest.MD5();
++            // END android-changed
++        }
++        // BEGIN android-removed
++        // if (sha224.contains(digestName))
++        // {
++        //     return new SHA224Digest();
++        // }
++        // END android-removed
+         if (sha256.contains(digestName))
+         {
+-            return new SHA256Digest();
++            // BEGIN android-changed
++            return new OpenSSLDigest.SHA256();
++            // END android-changed
+         }
+         if (sha384.contains(digestName))
+         {
+-            return new SHA384Digest();
++            // BEGIN android-changed
++            return new OpenSSLDigest.SHA384();
++            // END android-changed
+         }
+         if (sha512.contains(digestName))
+         {
+-            return new SHA512Digest();
++            // BEGIN android-changed
++            return new OpenSSLDigest.SHA512();
++            // END android-changed
+         }
+         
+         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-147.orig/org/bouncycastle/jce/ECNamedCurveTable.java bcprov-jdk15on-147/org/bouncycastle/jce/ECNamedCurveTable.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/ECNamedCurveTable.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/ECNamedCurveTable.java	2012-09-11 00:12:44.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;
@@ -990,7 +5767,7 @@
 -            {
 -                try
 -                {
--                    ecP = TeleTrusTNamedCurves.getByOID(new DERObjectIdentifier(name));
+-                    ecP = TeleTrusTNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
 -                }
 -                catch (IllegalArgumentException e)
 -                {
@@ -1006,7 +5783,7 @@
 +        //     {
 +        //         try
 +        //         {
-+        //             ecP = TeleTrusTNamedCurves.getByOID(new DERObjectIdentifier(name));
++        //             ecP = TeleTrusTNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
 +        //         }
 +        //         catch (IllegalArgumentException e)
 +        //         {
@@ -1029,10 +5806,21 @@
  
          return v.elements();
      }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk16-146/org/bouncycastle/jce/PKCS10CertificationRequest.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/PKCS10CertificationRequest.java	2012-07-27 18:48:00.041479127 +0000
-@@ -80,15 +80,20 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk15on-147/org/bouncycastle/jce/PKCS10CertificationRequest.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/PKCS10CertificationRequest.java	2012-09-11 00:12:44.000000000 +0000
+@@ -37,7 +37,9 @@
+ import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
+ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// END android-removed
+ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+ import org.bouncycastle.asn1.x509.X509Name;
+@@ -81,15 +83,20 @@
  
      static
      {
@@ -1057,7 +5845,7 @@
          algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
          algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
          algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
-@@ -96,57 +101,78 @@
+@@ -97,57 +104,78 @@
          algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
          algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
          algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -1156,7 +5944,7 @@
          oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
          
          //
-@@ -160,35 +186,53 @@
+@@ -161,35 +189,53 @@
          // The parameters field SHALL be NULL for RSA based signature algorithms.
          //
          noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
@@ -1221,7 +6009,7 @@
          params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
      }
  
-@@ -594,10 +638,12 @@
+@@ -595,10 +641,12 @@
          {
              return "SHA1";
          }
@@ -1238,7 +6026,7 @@
          else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
          {
              return "SHA256";
-@@ -610,22 +656,24 @@
+@@ -611,22 +659,24 @@
          {
              return "SHA512";
          }
@@ -1279,12 +6067,12 @@
          else
          {
              return digestAlgOID.getId();            
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk16-146/org/bouncycastle/jce/provider/BouncyCastleProvider.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2012-07-27 18:48:00.031478939 +0000
-@@ -45,7 +45,10 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2012-09-11 00:12:44.000000000 +0000
+@@ -48,7 +48,10 @@
  {
-     private static String info = "BouncyCastle Security Provider v1.46";
+     private static String info = "BouncyCastle Security Provider v1.47";
  
 -    public static String PROVIDER_NAME = "BC";
 +    // BEGIN android-changed
@@ -1292,27 +6080,54 @@
 +    public static final String PROVIDER_NAME = "BC";
 +    // END android-changed
  
-     /*
-      * Configurable symmetric ciphers
-@@ -53,8 +56,14 @@
-     private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.symmetric.";
+     public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
+ 
+@@ -61,8 +64,13 @@
+     private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric.";
      private static final String[] SYMMETRIC_CIPHERS =
      {
--        "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
--        "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
+-        "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"
 +        // BEGIN android-removed
-+        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
-+        // "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
++        // "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"
 +        // END android-removed
 +        // BEGIN android-added
-+        "AES", "ARC4", "Blowfish", "DESede",
++        "AES", "ARC4", "Blowfish", "DES", "DESede",
 +        // END android-added
-+
+     };
+ 
+      /*
+@@ -79,7 +87,12 @@
+ 
+     private static final String[] ASYMMETRIC_CIPHERS =
+     {
+-        "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal"
++        // BEGIN android-removed
++        // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal"
++        // END android-removed
++        // BEGIN android-added
++        "DSA", "DH", "EC", "RSA",
++        // END android-added
      };
  
      /*
-@@ -90,26 +99,28 @@
-         loadAlgorithms(SYMMETRIC_CIPHER_PACKAGE, SYMMETRIC_CIPHERS);
+@@ -88,7 +101,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", "Tiger", "Whirlpool"
++        // BEGIN android-removed
++        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "Tiger", "Whirlpool"
++        // END android-removed
++        // BEGIN android-added
++        "MD5", "SHA1", "SHA256", "SHA384", "SHA512",
++        // END android-added
+     };
+ 
+     /**
+@@ -120,26 +138,28 @@
+ 
          loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_CIPHERS);
  
 -        //
@@ -1360,7 +6175,7 @@
  
  
          //
-@@ -118,14 +129,24 @@
+@@ -148,14 +168,24 @@
          put("KeyStore.BKS", "org.bouncycastle.jce.provider.JDKKeyStore");
          put("KeyStore.BouncyCastle", "org.bouncycastle.jce.provider.JDKKeyStore$BouncyCastleStore");
          put("KeyStore.PKCS12", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore");
@@ -1393,67 +6208,22 @@
  
          put("Alg.Alias.KeyStore.UBER", "BouncyCastle");
          put("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
-@@ -142,44 +163,63 @@
-         //
-         put("AlgorithmParameterGenerator.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DH");
-         put("AlgorithmParameterGenerator.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DSA");
--        put("AlgorithmParameterGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$GOST3410");
--        put("AlgorithmParameterGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$ElGamal");
--        put("AlgorithmParameterGenerator.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
--        put("AlgorithmParameterGenerator.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
--        put("AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
--        put("AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
--        put("AlgorithmParameterGenerator.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
--        put("AlgorithmParameterGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
-+        // BEGIN android-removed
-+        // put("AlgorithmParameterGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$GOST3410");
-+        // put("AlgorithmParameterGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$ElGamal");
-+        // put("AlgorithmParameterGenerator.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-+        // put("AlgorithmParameterGenerator.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-+        // put("AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-+        // put("AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-+        // put("AlgorithmParameterGenerator.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
-+        // put("AlgorithmParameterGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
-+        // END android-removed
- 
-         put("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH");
--        put("Alg.Alias.AlgorithmParameterGenerator.GOST-3410", "GOST3410");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.AlgorithmParameterGenerator.GOST-3410", "GOST3410");
-+        // END android-removed
+@@ -164,29 +194,41 @@
          //
          // algorithm parameters
          //
-         put("AlgorithmParameters.OAEP", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$OAEP");
--        put("AlgorithmParameters.PSS", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PSS");
-+        // BEGIN android-removed
-+        // put("AlgorithmParameters.PSS", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PSS");
-+        // END android-removed
-         put("AlgorithmParameters.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$DH");
-         put("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH");
-         put("AlgorithmParameters.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$DSA");
--        put("AlgorithmParameters.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$ElGamal");
 -        put("AlgorithmParameters.IES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IES");
 +        // BEGIN android-removed
-+        // put("AlgorithmParameters.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$ElGamal");
 +        // put("AlgorithmParameters.IES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IES");
 +        // END android-removed
          put("AlgorithmParameters.PKCS12PBE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PKCS12PBE");
--        put("AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+ 
 -        put("AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PBKDF2");
--
--        put("AlgorithmParameters.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$GOST3410");
--        put("Alg.Alias.AlgorithmParameters.GOST-3410", "GOST3410");
-+        // BEGIN android-changed
-+        // redundant with below
-+        // put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
-+        // END android-changed
 +        // BEGIN android-removed
 +        // put("AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PBKDF2");
-+        //
-+        // put("AlgorithmParameters.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$GOST3410");
-+        // put("Alg.Alias.AlgorithmParameters.GOST-3410", "GOST3410");
 +        // END android-removed
+ 
+ 
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
 -        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE");
 -        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE");
@@ -1481,57 +6251,16 @@
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
-@@ -193,7 +233,7 @@
-         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
-         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
-         put("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
--
-+        
-         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
-         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
-         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
-@@ -203,22 +243,24 @@
- 
-         put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
-         
--        put("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
--        put("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
--        put("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
--        put("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
+         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC4", "PKCS12PBE");
+         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+-        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
 +        // BEGIN android-removed
-+        // put("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
-+        // put("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
++        // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
 +        // END android-removed
-         
-         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
-         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
-@@ -235,12 +277,14 @@
+         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.1", "PKCS12PBE");
+         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.2", "PKCS12PBE");
+         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3", "PKCS12PBE");
+@@ -217,12 +259,14 @@
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE");
@@ -1552,95 +6281,19 @@
          
          //
          // key agreement
-@@ -252,71 +296,91 @@
-         // cipher engines
-         //
-         put("Cipher.DES", "org.bouncycastle.jce.provider.JCEBlockCipher$DES");
--        put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
--
--        put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
--        put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
--        put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
--
--        put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
-+        // BEGIN android-removed
-+        // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
-+        //
-+        // put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
-+        // put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
-+        // put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
-+        //
-+        // put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
-+        // END android-removed
-         
+@@ -235,16 +279,22 @@
          put("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES",  "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
          
--        put("Cipher.GOST28147", "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147");
--        put("Alg.Alias.Cipher.GOST", "GOST28147");
--        put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
--        put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
-+        // BEGIN android-removed
-+        // put("Cipher.GOST28147", "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147");
-+        // put("Alg.Alias.Cipher.GOST", "GOST28147");
-+        // put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
-+        // put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
-+        // END android-removed
  
-         put("Cipher.RSA", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
--        put("Cipher.RSA/RAW", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
--        put("Cipher.RSA/PKCS1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
--        put("Cipher.1.2.840.113549.1.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
--        put("Cipher.2.5.8.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
--        put("Cipher.RSA/1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PrivateOnly");
--        put("Cipher.RSA/2", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PublicOnly");
--        put("Cipher.RSA/OAEP", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
--        put("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
--        put("Cipher.RSA/ISO9796-1", "org.bouncycastle.jce.provider.JCERSACipher$ISO9796d1Padding");
--
 -        put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
 -        put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
 -        put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
 -        put("Cipher.BrokenIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenIES");
--        put("Cipher.ELGAMAL", "org.bouncycastle.jce.provider.JCEElGamalCipher$NoPadding");
--        put("Cipher.ELGAMAL/PKCS1", "org.bouncycastle.jce.provider.JCEElGamalCipher$PKCS1v1_5Padding");
-+        // BEGIN android-changed
-+        put("Alg.Alias.Cipher.RSA/RAW", "RSA");
-+        // END android-changed
 +        // BEGIN android-removed
-+        // put("Cipher.RSA/PKCS1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
-+        // put("Cipher.1.2.840.113549.1.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
-+        // put("Cipher.2.5.8.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
-+        // put("Cipher.RSA/1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PrivateOnly");
-+        // put("Cipher.RSA/2", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PublicOnly");
-+        // put("Cipher.RSA/OAEP", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
-+        // put("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
-+        // put("Cipher.RSA/ISO9796-1", "org.bouncycastle.jce.provider.JCERSACipher$ISO9796d1Padding");
-+        //
 +        // put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
 +        // put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
 +        // put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
 +        // put("Cipher.BrokenIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenIES");
-+        // put("Cipher.ELGAMAL", "org.bouncycastle.jce.provider.JCEElGamalCipher$NoPadding");
-+        // put("Cipher.ELGAMAL/PKCS1", "org.bouncycastle.jce.provider.JCEElGamalCipher$PKCS1v1_5Padding");
-+        // END android-removed
- 
-         put("Alg.Alias.Cipher.RSA//RAW", "RSA");
-         put("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
--        put("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
--        put("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
--        put("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
--        
--        put("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
--        put("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
--        put("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
-+        // put("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
-+        // put("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
-+        //
-+        // put("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
-+        // put("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
-+        // put("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
 +        // END android-removed
  
          put("Cipher.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithMD5AndDES");
@@ -1655,50 +6308,9 @@
 +        // put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
 +        // END android-removed
          put("Cipher.PBEWITHSHA1ANDRC2", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHA1AndRC2");
-         put("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndDES3Key");
--        put("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES3Key");
--        put("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndDES3Key");
-+        // BEGIN android-removed
-+        // put("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES3Key");
-+        // put("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndDES3Key");
-+        // END android-removed
-         put("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndDES2Key");
--        put("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES2Key");
-+        // BEGIN android-removed
-+        // put("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES2Key");
-+        // END android-removed
+ 
          put("Cipher.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd128BitRC2");
-         put("Cipher.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd40BitRC2");
-         put("Cipher.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd128BitRC4");
-         put("Cipher.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd40BitRC4");
- 
--        put("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
--        put("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
--        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "Cipher.PBEWITHSHAAND128BITRC2-CBC");
--        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "Cipher.PBEWITHSHAAND40BITRC2-CBC");
--        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "Cipher.PBEWITHSHAAND128BITRC4");
--        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "Cipher.PBEWITHSHAAND40BITRC4");
-+        // BEGIN android-changed
-+        put("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
-+        put("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
-+        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
-+        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
-+        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
-+        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
-+        // END android-changed
- 
-         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
-         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
-@@ -324,7 +388,7 @@
-         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
-         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
-         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
--
-+        
-         put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
-         put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
-         put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
-@@ -346,10 +410,12 @@
+@@ -286,10 +336,12 @@
          put("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          
          put("Cipher.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndTwofish");
@@ -1715,113 +6327,17 @@
          put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
          put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
          put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
-@@ -368,13 +434,15 @@
-         put("KeyGenerator.DES", "org.bouncycastle.jce.provider.JCEKeyGenerator$DES");
-         put("Alg.Alias.KeyGenerator." + OIWObjectIdentifiers.desCBC, "DES");
- 
--        put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
--        put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
--
--        put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
--        put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
--        put("Alg.Alias.KeyGenerator.GOST-28147", "GOST28147");
--        put("Alg.Alias.KeyGenerator." + CryptoProObjectIdentifiers.gostR28147_cbc, "GOST28147");
-+        // BEGIN android-removed
-+        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-+        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-+        //
-+        // put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
-+        // put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
-+        // put("Alg.Alias.KeyGenerator.GOST-28147", "GOST28147");
-+        // put("Alg.Alias.KeyGenerator." + CryptoProObjectIdentifiers.gostR28147_cbc, "GOST28147");
-+        // END android-removed
- 
-         //
-         // key pair generators.
-@@ -382,14 +450,18 @@
-         put("KeyPairGenerator.RSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$RSA");
-         put("KeyPairGenerator.DH", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DH");
-         put("KeyPairGenerator.DSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DSA");
--        put("KeyPairGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ElGamal");
-+        // BEGIN android-removed
-+        // put("KeyPairGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ElGamal");
-+        // END android-removed
- 
-         put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.1", "RSA");
-         put("Alg.Alias.KeyPairGenerator.DIFFIEHELLMAN", "DH");
-         
--        put("KeyPairGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$GOST3410");
--        put("Alg.Alias.KeyPairGenerator.GOST-3410", "GOST3410");
--        put("Alg.Alias.KeyPairGenerator.GOST-3410-94", "GOST3410");
-+        // BEGIN android-removed
-+        // put("KeyPairGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$GOST3410");
-+        // put("Alg.Alias.KeyPairGenerator.GOST-3410", "GOST3410");
-+        // put("Alg.Alias.KeyPairGenerator.GOST-3410-94", "GOST3410");
-+        // END android-removed
- 
-         //
-         // key factories
-@@ -397,20 +469,24 @@
-         put("KeyFactory.RSA", "org.bouncycastle.jce.provider.JDKKeyFactory$RSA");
-         put("KeyFactory.DH", "org.bouncycastle.jce.provider.JDKKeyFactory$DH");
-         put("KeyFactory.DSA", "org.bouncycastle.jce.provider.JDKKeyFactory$DSA");
--        put("KeyFactory.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
--        put("KeyFactory.ElGamal", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
--
--        put("KeyFactory.X.509", "org.bouncycastle.jce.provider.JDKKeyFactory$X509");
-+        // BEGIN android-removed
-+        // put("KeyFactory.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
-+        // put("KeyFactory.ElGamal", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
-+        //
-+        // put("KeyFactory.X.509", "org.bouncycastle.jce.provider.JDKKeyFactory$X509");
-+        // END android-removed
-         
-         put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA");
-         put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA");
- 
-         put("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH");
- 
--        put("KeyFactory.GOST3410", "org.bouncycastle.jce.provider.JDKKeyFactory$GOST3410");
--        put("Alg.Alias.KeyFactory.GOST-3410", "GOST3410");
--        put("Alg.Alias.KeyFactory.GOST-3410-94", "GOST3410");
--        put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_94, "GOST3410");
-+        // BEGIN android-removed
-+        // put("KeyFactory.GOST3410", "org.bouncycastle.jce.provider.JDKKeyFactory$GOST3410");
-+        // put("Alg.Alias.KeyFactory.GOST-3410", "GOST3410");
-+        // put("Alg.Alias.KeyFactory.GOST-3410-94", "GOST3410");
-+        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_94, "GOST3410");
-+        // END android-removed
- 
-         //
-         // Algorithm parameters
-@@ -418,24 +494,34 @@
-         put("AlgorithmParameters.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-         put("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
-         put("AlgorithmParameters.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
--        put("AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
--        put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
--        put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-+        // BEGIN android-changed
-+        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
-+        // END android-changed
-+        // BEGIN android-removed
-+        // put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-+        // put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-+        // END android-removed
-         
+@@ -326,16 +378,20 @@
          //
          // secret key factories.
          //
-         put("SecretKeyFactory.DES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DES");
 -        put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
 -
 -        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
 -        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
 +        // BEGIN android-removed
 +        // put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
-+        // END android-removed
-+
-+        // BEGIN android-removed
++        //
 +        // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
 +        // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
 +        // END android-removed
@@ -1837,7 +6353,7 @@
          put("SecretKeyFactory.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndDES");
          put("SecretKeyFactory.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndRC2");
          put("SecretKeyFactory.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndDES");
-@@ -447,31 +533,41 @@
+@@ -347,31 +403,39 @@
          put("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC2");
          put("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC2");
          put("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndTwofish");
@@ -1875,9 +6391,7 @@
 +        // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PBE/PKCS12");
 +        // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBE/PKCS12");
 +        // put("Alg.Alias.SecretKeyFactory.OLDPBEWITHSHAANDTWOFISH-CBC", "PBE/PKCS12");
-+        // END android-removed
-+
-+        // BEGIN android-removed
++        //
 +        // put("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
 +        // put("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDRC2-CBC", "PBEWITHMD2ANDRC2");
 +        // END android-removed
@@ -1894,7 +6408,7 @@
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
-@@ -508,6 +604,10 @@
+@@ -408,20 +472,31 @@
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
@@ -1905,9 +6419,6 @@
  
          addMacAlgorithms();
  
-@@ -516,16 +616,23 @@
-         addSignatureAlgorithms();
- 
      // Certification Path API
 -        put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
 -        put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
@@ -1936,15 +6447,10 @@
      }
  
      private void loadAlgorithms(String packageName, String[] names)
-@@ -586,42 +693,46 @@
-     //
+@@ -469,21 +544,25 @@
      private void addMacAlgorithms()
      {
--        put("Mac.DESMAC", "org.bouncycastle.jce.provider.JCEMac$DES");
--        put("Alg.Alias.Mac.DES", "DESMAC");
--        put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
--        put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
--
+ 
 -        put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
 -        put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
 -
@@ -1953,27 +6459,10 @@
 -        put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
 -        put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
 -
--        put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
--        put("Alg.Alias.Mac.RC2", "RC2MAC");
--        put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
--        put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
--
--
--        put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
--        put("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
--
 -        put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
 -
 -        put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
--
--        addHMACAlgorithm("MD2", "org.bouncycastle.jce.provider.JCEMac$MD2", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD2HMAC");
--        addHMACAlgorithm("MD4", "org.bouncycastle.jce.provider.JCEMac$MD4", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD4HMAC");
 +        // BEGIN android-removed
-+        // put("Mac.DESMAC", "org.bouncycastle.jce.provider.JCEMac$DES");
-+        // put("Alg.Alias.Mac.DES", "DESMAC");
-+        // put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
-+        // put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
-+        //
 +        // put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
 +        // put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
 +        //
@@ -1982,54 +6471,9 @@
 +        // put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
 +        // put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
 +        //
-+        // put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
-+        // put("Alg.Alias.Mac.RC2", "RC2MAC");
-+        // put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
-+        // put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
-+        //
-+        //
-+        // put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
-+        // put("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
-+        //
 +        // put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
 +        //
 +        // put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
-+        //
-+        // addHMACAlgorithm("MD2", "org.bouncycastle.jce.provider.JCEMac$MD2", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD2HMAC");
-+        // addHMACAlgorithm("MD4", "org.bouncycastle.jce.provider.JCEMac$MD4", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD4HMAC");
-+        // END android-removed
-         addHMACAlgorithm("MD5", "org.bouncycastle.jce.provider.JCEMac$MD5", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD5HMAC");
-         addHMACAlias("MD5", IANAObjectIdentifiers.hmacMD5);
- 
-         addHMACAlgorithm("SHA1", "org.bouncycastle.jce.provider.JCEMac$SHA1", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA1");
-         addHMACAlias("SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
-         addHMACAlias("SHA1", IANAObjectIdentifiers.hmacSHA1);
--        addHMACAlgorithm("SHA224", "org.bouncycastle.jce.provider.JCEMac$SHA224", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA224");
--        addHMACAlias("SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
-+        // BEGIN android-removed
-+        // addHMACAlgorithm("SHA224", "org.bouncycastle.jce.provider.JCEMac$SHA224", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA224");
-+        // addHMACAlias("SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
-+        // END android-removed
-         addHMACAlgorithm("SHA256", "org.bouncycastle.jce.provider.JCEMac$SHA256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA256");
-         addHMACAlias("SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
-         addHMACAlgorithm("SHA384", "org.bouncycastle.jce.provider.JCEMac$SHA384", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA384");
-@@ -629,16 +740,20 @@
-         addHMACAlgorithm("SHA512", "org.bouncycastle.jce.provider.JCEMac$SHA512", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA512");
-         addHMACAlias("SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
- 
--        addHMACAlgorithm("RIPEMD128", "org.bouncycastle.jce.provider.JCEMac$RIPEMD128", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD128HMAC");
--        addHMACAlgorithm("RIPEMD160", "org.bouncycastle.jce.provider.JCEMac$RIPEMD160", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD160HMAC");
--        addHMACAlias("RIPEMD160", IANAObjectIdentifiers.hmacRIPEMD160);
--
--        addHMACAlgorithm("TIGER", "org.bouncycastle.jce.provider.JCEMac$Tiger", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACTIGER");
--        addHMACAlias("TIGER", IANAObjectIdentifiers.hmacTIGER);
-+        // BEGIN android-removed
-+        // addHMACAlgorithm("RIPEMD128", "org.bouncycastle.jce.provider.JCEMac$RIPEMD128", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD128HMAC");
-+        // addHMACAlgorithm("RIPEMD160", "org.bouncycastle.jce.provider.JCEMac$RIPEMD160", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD160HMAC");
-+        // addHMACAlias("RIPEMD160", IANAObjectIdentifiers.hmacRIPEMD160);
-+        //
-+        // addHMACAlgorithm("TIGER", "org.bouncycastle.jce.provider.JCEMac$Tiger", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACTIGER");
-+        // addHMACAlias("TIGER", IANAObjectIdentifiers.hmacTIGER);
 +        // END android-removed
  
          put("Mac.PBEWITHHMACSHA", "org.bouncycastle.jce.provider.JCEMac$PBEWithSHA");
@@ -2041,411 +6485,9 @@
          put("Alg.Alias.Mac.1.3.14.3.2.26", "PBEWITHHMACSHA");
      }
  
-@@ -676,9 +791,11 @@
-         put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
-         put("Alg.Alias.MessageDigest.SHA", "SHA-1");
-         put("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
--        put("MessageDigest.SHA-224", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA224");
--        put("Alg.Alias.MessageDigest.SHA224", "SHA-224");
--        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
-+        // BEGIN android-removed
-+        // put("MessageDigest.SHA-224", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA224");
-+        // put("Alg.Alias.MessageDigest.SHA224", "SHA-224");
-+        // put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
-+        // END android-removed
-         put("MessageDigest.SHA-256", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA256");
-         put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
-         put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
-@@ -689,27 +806,31 @@
-         put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
-         put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
-         
--        put("MessageDigest.MD2", "org.bouncycastle.jce.provider.JDKMessageDigest$MD2");
--        put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md2, "MD2");
--        put("MessageDigest.MD4", "org.bouncycastle.jce.provider.JDKMessageDigest$MD4");
--        put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md4, "MD4");
-+        // BEGIN android-removed
-+        // put("MessageDigest.MD2", "org.bouncycastle.jce.provider.JDKMessageDigest$MD2");
-+        // put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md2, "MD2");
-+        // put("MessageDigest.MD4", "org.bouncycastle.jce.provider.JDKMessageDigest$MD4");
-+        // put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md4, "MD4");
-+        // END android-removed
-         put("MessageDigest.MD5", "org.bouncycastle.jce.provider.JDKMessageDigest$MD5");
-         put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
--        put("MessageDigest.RIPEMD128", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD128");
--        put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
--        put("MessageDigest.RIPEMD160", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD160");
--        put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
--        put("MessageDigest.RIPEMD256", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD256");
--        put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
--        put("MessageDigest.RIPEMD320", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD320");
--        put("MessageDigest.Tiger", "org.bouncycastle.jce.provider.JDKMessageDigest$Tiger");
--        
--        put("MessageDigest.WHIRLPOOL", "org.bouncycastle.jce.provider.JDKMessageDigest$Whirlpool");
--        
--        put("MessageDigest.GOST3411", "org.bouncycastle.jce.provider.JDKMessageDigest$GOST3411");
--        put("Alg.Alias.MessageDigest.GOST", "GOST3411");
--        put("Alg.Alias.MessageDigest.GOST-3411", "GOST3411");
--        put("Alg.Alias.MessageDigest." + CryptoProObjectIdentifiers.gostR3411, "GOST3411");
-+        // BEGIN android-removed
-+        // put("MessageDigest.RIPEMD128", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD128");
-+        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
-+        // put("MessageDigest.RIPEMD160", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD160");
-+        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
-+        // put("MessageDigest.RIPEMD256", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD256");
-+        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
-+        // put("MessageDigest.RIPEMD320", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD320");
-+        // put("MessageDigest.Tiger", "org.bouncycastle.jce.provider.JDKMessageDigest$Tiger");
-+        
-+        // put("MessageDigest.WHIRLPOOL", "org.bouncycastle.jce.provider.JDKMessageDigest$Whirlpool");
-+        
-+        // put("MessageDigest.GOST3411", "org.bouncycastle.jce.provider.JDKMessageDigest$GOST3411");
-+        // put("Alg.Alias.MessageDigest.GOST", "GOST3411");
-+        // put("Alg.Alias.MessageDigest.GOST-3411", "GOST3411");
-+        // put("Alg.Alias.MessageDigest." + CryptoProObjectIdentifiers.gostR3411, "GOST3411");
-+        // END android-removed
-     }
-     
-     //
-@@ -717,55 +838,70 @@
-     //
-     private void addSignatureAlgorithms()
-     {
--        put("Signature.MD2WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD2WithRSAEncryption");
--        put("Signature.MD4WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD4WithRSAEncryption");
-+        // BEGIN android-removed
-+        // Dropping MD2
-+        // put("Signature.MD2WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD2WithRSAEncryption");
-+        // put("Signature.MD4WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD4WithRSAEncryption");
-+        // END android-removed
-         put("Signature.MD5WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD5WithRSAEncryption");
-         put("Signature.SHA1WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA1WithRSAEncryption");
--        put("Signature.SHA224WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA224WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Signature.SHA224WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA224WithRSAEncryption");
-+        // END android-removed
-         put("Signature.SHA256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA256WithRSAEncryption");
-         put("Signature.SHA384WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA384WithRSAEncryption");
-         put("Signature.SHA512WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA512WithRSAEncryption");
--        put("Signature.RIPEMD160WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD160WithRSAEncryption");
--        put("Signature.RIPEMD128WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD128WithRSAEncryption");
--        put("Signature.RIPEMD256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD256WithRSAEncryption");
--        put("Signature.DSA", "org.bouncycastle.jce.provider.JDKDSASigner$stdDSA");
-+        // BEGIN android-removed
-+        // put("Signature.RIPEMD160WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD160WithRSAEncryption");
-+        // put("Signature.RIPEMD128WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD128WithRSAEncryption");
-+        // put("Signature.RIPEMD256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD256WithRSAEncryption");
-+        // END android-removed
-+        // BEGIN android-changed
-+        put("Signature.SHA1withDSA", "org.bouncycastle.jce.provider.JDKDSASigner$stdDSA");
-+        // END android-changed
-         put("Signature.NONEWITHDSA", "org.bouncycastle.jce.provider.JDKDSASigner$noneDSA");
--        put("Signature.SHA1withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$SHA1WithRSAEncryption");
--        put("Signature.MD5withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$MD5WithRSAEncryption");
--        put("Signature.RIPEMD160withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$RIPEMD160WithRSAEncryption");
--
--        put("Signature.RSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
--        put("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
--        put("Signature.SHA1withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA1withRSA");
--        put("Signature.SHA224withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA224withRSA");
--        put("Signature.SHA256withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA256withRSA");
--        put("Signature.SHA384withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA384withRSA");
--        put("Signature.SHA512withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA512withRSA");
--
--        put("Signature.RSA", "org.bouncycastle.jce.provider.JDKDigestSignature$noneRSA");
--        put("Signature.RAWRSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$nonePSS");
-+        // BEGIN android-removed
-+        // put("Signature.SHA1withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$SHA1WithRSAEncryption");
-+        // put("Signature.MD5withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$MD5WithRSAEncryption");
-+        // put("Signature.RIPEMD160withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$RIPEMD160WithRSAEncryption");
-+        //
-+        // put("Signature.RSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
-+        // put("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
-+        // put("Signature.SHA1withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA1withRSA");
-+        // put("Signature.SHA224withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA224withRSA");
-+        // put("Signature.SHA256withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA256withRSA");
-+        // put("Signature.SHA384withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA384withRSA");
-+        // put("Signature.SHA512withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA512withRSA");
-+        //
-+        // put("Signature.RSA", "org.bouncycastle.jce.provider.JDKDigestSignature$noneRSA");
-+        // put("Signature.RAWRSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$nonePSS");
-+        // END android-removed
- 
-         put("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
- 
--        put("Alg.Alias.Signature.RAWRSA", "RSA");
--        put("Alg.Alias.Signature.NONEWITHRSA", "RSA");
--        put("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
--        put("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
--        put("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
--
--        put("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
--
--        put("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
--        put("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
--        put("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
--        put("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
--        put("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
--        
--        put("Alg.Alias.Signature.MD2withRSAEncryption", "MD2WithRSAEncryption");
--        put("Alg.Alias.Signature.MD4withRSAEncryption", "MD4WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.RAWRSA", "RSA");
-+        // put("Alg.Alias.Signature.NONEWITHRSA", "RSA");
-+        // put("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
-+        // put("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
-+        // put("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
-+        //
-+        // put("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
-+        //
-+        // put("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
-+        // put("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
-+        // put("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
-+        // put("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
-+        // put("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
-+        //
-+        // put("Alg.Alias.Signature.MD2withRSAEncryption", "MD2WithRSAEncryption");
-+        // put("Alg.Alias.Signature.MD4withRSAEncryption", "MD4WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature.MD5withRSAEncryption", "MD5WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA1withRSAEncryption", "SHA1WithRSAEncryption");
--        put("Alg.Alias.Signature.SHA224withRSAEncryption", "SHA224WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.SHA224withRSAEncryption", "SHA224WithRSAEncryption");
-+        // END android-removed
- 
-         put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384WithRSAEncryption");
-@@ -779,24 +915,30 @@
-         put("Alg.Alias.Signature.SHA384WITHRSAENCRYPTION", "SHA384WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA512WITHRSAENCRYPTION", "SHA512WithRSAEncryption");
- 
--        put("Alg.Alias.Signature.RIPEMD160withRSAEncryption", "RIPEMD160WithRSAEncryption");
--
--        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WithRSAEncryption");
--        put("Alg.Alias.Signature.MD2WithRSA", "MD2WithRSAEncryption");
--        put("Alg.Alias.Signature.MD2withRSA", "MD2WithRSAEncryption");
--        put("Alg.Alias.Signature.MD2/RSA", "MD2WithRSAEncryption");
-+        // BEGIN android-removed
-+        // Dropping MD2
-+        // put("Alg.Alias.Signature.RIPEMD160withRSAEncryption", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WithRSAEncryption");
-+        // put("Alg.Alias.Signature.MD2WithRSA", "MD2WithRSAEncryption");
-+        // put("Alg.Alias.Signature.MD2withRSA", "MD2WithRSAEncryption");
-+        // put("Alg.Alias.Signature.MD2/RSA", "MD2WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature.MD5WithRSA", "MD5WithRSAEncryption");
-         put("Alg.Alias.Signature.MD5withRSA", "MD5WithRSAEncryption");
-         put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSAEncryption");
-         put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WithRSAEncryption");
--        put("Alg.Alias.Signature.MD4WithRSA", "MD4WithRSAEncryption");
--        put("Alg.Alias.Signature.MD4withRSA", "MD4WithRSAEncryption");
--        put("Alg.Alias.Signature.MD4/RSA", "MD4WithRSAEncryption");
--        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.MD4WithRSA", "MD4WithRSAEncryption");
-+        // put("Alg.Alias.Signature.MD4withRSA", "MD4WithRSAEncryption");
-+        // put("Alg.Alias.Signature.MD4/RSA", "MD4WithRSAEncryption");
-+        // put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA1withRSA", "SHA1WithRSAEncryption");
--        put("Alg.Alias.Signature.SHA224WithRSA", "SHA224WithRSAEncryption");
--        put("Alg.Alias.Signature.SHA224withRSA", "SHA224WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.SHA224WithRSA", "SHA224WithRSAEncryption");
-+        // put("Alg.Alias.Signature.SHA224withRSA", "SHA224WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA256withRSA", "SHA256WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
-@@ -806,92 +948,110 @@
-         put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
-         put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WithRSAEncryption");
--        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WithRSAEncryption");
-         put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WithRSAEncryption");
-         put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WithRSAEncryption");
-         put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSAEncryption");
-         put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
-         put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD160WithRSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD160withRSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD128WithRSA", "RIPEMD128WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD128withRSA", "RIPEMD128WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD256WithRSA", "RIPEMD256WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD256withRSA", "RIPEMD256WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD-160/RSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.RMD160withRSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.RMD160/RSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.1.3.36.3.3.1.2", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.1.3.36.3.3.1.3", "RIPEMD128WithRSAEncryption");
--        put("Alg.Alias.Signature.1.3.36.3.3.1.4", "RIPEMD256WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.RIPEMD160WithRSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD160withRSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD128WithRSA", "RIPEMD128WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD128withRSA", "RIPEMD128WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD256WithRSA", "RIPEMD256WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD256withRSA", "RIPEMD256WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD-160/RSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RMD160withRSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RMD160/RSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.1.3.36.3.3.1.2", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.1.3.36.3.3.1.3", "RIPEMD128WithRSAEncryption");
-+        // put("Alg.Alias.Signature.1.3.36.3.3.1.4", "RIPEMD256WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WithRSAEncryption");
-         
--        put("Alg.Alias.Signature.MD2WITHRSAENCRYPTION", "MD2WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.MD2WITHRSAENCRYPTION", "MD2WithRSAEncryption");
-+        // END android-removed
-         put("Alg.Alias.Signature.MD5WITHRSAENCRYPTION", "MD5WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA1WITHRSAENCRYPTION", "SHA1WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD160WITHRSAENCRYPTION", "RIPEMD160WithRSAEncryption");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.RIPEMD160WITHRSAENCRYPTION", "RIPEMD160WithRSAEncryption");
-+        // END android-removed
- 
-         put("Alg.Alias.Signature.MD5WITHRSA", "MD5WithRSAEncryption");
-         put("Alg.Alias.Signature.SHA1WITHRSA", "SHA1WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.RMD160WITHRSA", "RIPEMD160WithRSAEncryption");
--        put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
--
--        addSignatureAlgorithm("SHA224", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
--        addSignatureAlgorithm("SHA256", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
--        addSignatureAlgorithm("SHA384", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
--        addSignatureAlgorithm("SHA512", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
--
--        put("Alg.Alias.Signature.SHA/DSA", "DSA");
--        put("Alg.Alias.Signature.SHA1withDSA", "DSA");
--        put("Alg.Alias.Signature.SHA1WITHDSA", "DSA");
--        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "DSA");
--        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "DSA");
--        put("Alg.Alias.Signature.DSAwithSHA1", "DSA");
--        put("Alg.Alias.Signature.DSAWITHSHA1", "DSA");
--        put("Alg.Alias.Signature.SHA1WithDSA", "DSA");
--        put("Alg.Alias.Signature.DSAWithSHA1", "DSA");
--        put("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA");
--        put("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
--        put("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
--        put("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
--        
--        put("Signature.ECGOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$ecgost3410");
--        put("Alg.Alias.Signature.ECGOST-3410", "ECGOST3410");
--        put("Alg.Alias.Signature.GOST-3410-2001", "ECGOST3410");
--        put("Alg.Alias.Signature.GOST3411withECGOST3410", "ECGOST3410");
--        put("Alg.Alias.Signature.GOST3411WITHECGOST3410", "ECGOST3410");
--        put("Alg.Alias.Signature.GOST3411WithECGOST3410", "ECGOST3410");
--        put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "ECGOST3410");
--        
--        put("Signature.GOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$gost3410");
--        put("Alg.Alias.Signature.GOST-3410", "GOST3410");
--        put("Alg.Alias.Signature.GOST-3410-94", "GOST3410");
--        put("Alg.Alias.Signature.GOST3411withGOST3410", "GOST3410");
--        put("Alg.Alias.Signature.GOST3411WITHGOST3410", "GOST3410");
--        put("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
--        put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
--    }
--
--    private void addSignatureAlgorithm(
--        String digest,
--        String algorithm,
--        String className,
--        DERObjectIdentifier oid)
--    {
--        String mainName = digest + "WITH" + algorithm;
--        String jdk11Variation1 = digest + "with" + algorithm;
--        String jdk11Variation2 = digest + "With" + algorithm;
--        String alias = digest + "/" + algorithm;
--
--        put("Signature." + mainName, className);
--        put("Alg.Alias.Signature." + jdk11Variation1, mainName);
--        put("Alg.Alias.Signature." + jdk11Variation2, mainName);
--        put("Alg.Alias.Signature." + alias, mainName);
--        put("Alg.Alias.Signature." + oid, mainName);
--        put("Alg.Alias.Signature.OID." + oid, mainName);
--    }
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RMD160WITHRSA", "RIPEMD160WithRSAEncryption");
-+        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
-+        // END android-removed
-+
-+        // BEGIN android-removed
-+        // addSignatureAlgorithm("SHA224", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
-+        // addSignatureAlgorithm("SHA256", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
-+        // addSignatureAlgorithm("SHA384", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
-+        // addSignatureAlgorithm("SHA512", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
-+        // END android-removed
-+
-+        // BEGIN android-changed
-+        put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
-+        put("Alg.Alias.Signature.DSA", "SHA1withDSA");
-+        put("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA");
-+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
-+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
-+        put("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA");
-+        put("Alg.Alias.Signature.DSAWITHSHA1", "SHA1withDSA");
-+        put("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA");
-+        put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
-+        put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
-+        // END android-changed
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
-+        // put("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
-+        // put("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
-+        //
-+        // put("Signature.ECGOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$ecgost3410");
-+        // put("Alg.Alias.Signature.ECGOST-3410", "ECGOST3410");
-+        // put("Alg.Alias.Signature.GOST-3410-2001", "ECGOST3410");
-+        // put("Alg.Alias.Signature.GOST3411withECGOST3410", "ECGOST3410");
-+        // put("Alg.Alias.Signature.GOST3411WITHECGOST3410", "ECGOST3410");
-+        // put("Alg.Alias.Signature.GOST3411WithECGOST3410", "ECGOST3410");
-+        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "ECGOST3410");
-+        //
-+        // put("Signature.GOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$gost3410");
-+        // put("Alg.Alias.Signature.GOST-3410", "GOST3410");
-+        // put("Alg.Alias.Signature.GOST-3410-94", "GOST3410");
-+        // put("Alg.Alias.Signature.GOST3411withGOST3410", "GOST3410");
-+        // put("Alg.Alias.Signature.GOST3411WITHGOST3410", "GOST3410");
-+        // put("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
-+        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
-+        // END android-removed
-+    }
-+
-+    // BEGIN android-removed
-+    // private void addSignatureAlgorithm(
-+    //     String digest,
-+    //     String algorithm,
-+    //     String className,
-+    //     DERObjectIdentifier oid)
-+    // {
-+    //     String mainName = digest + "WITH" + algorithm;
-+    //     String jdk11Variation1 = digest + "with" + algorithm;
-+    //     String jdk11Variation2 = digest + "With" + algorithm;
-+    //     String alias = digest + "/" + algorithm;
-+    //
-+    //     put("Signature." + mainName, className);
-+    //     put("Alg.Alias.Signature." + jdk11Variation1, mainName);
-+    //     put("Alg.Alias.Signature." + jdk11Variation2, mainName);
-+    //     put("Alg.Alias.Signature." + alias, mainName);
-+    //     put("Alg.Alias.Signature." + oid, mainName);
-+    //     put("Alg.Alias.Signature.OID." + oid, mainName);
-+    // }
-+    // END android-removed
- 
-     public void setParameter(String parameterName, Object parameter)
-     {
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/CertBlacklist.java bcprov-jdk16-146/org/bouncycastle/jce/provider/CertBlacklist.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/CertBlacklist.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/CertBlacklist.java	2012-07-27 18:48:00.031478939 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/CertBlacklist.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/CertBlacklist.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/CertBlacklist.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/CertBlacklist.java	2012-09-11 00:12:44.000000000 +0000
 @@ -0,0 +1,177 @@
 +/*
 + * Copyright (C) 2012 The Android Open Source Project
@@ -2624,20 +6666,12 @@
 +    }
 +
 +}
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk16-146/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2012-07-27 18:48:00.031478939 +0000
-@@ -24,6 +24,7 @@
- import java.security.spec.DSAPublicKeySpec;
- import java.text.ParseException;
- import java.util.ArrayList;
-+import java.util.Arrays;
- import java.util.Collection;
- import java.util.Date;
- import java.util.Enumeration;
-@@ -59,13 +60,17 @@
- import org.bouncycastle.asn1.x509.PolicyInformation;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2012-09-11 00:12:44.000000000 +0000
+@@ -61,13 +61,17 @@
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+ import org.bouncycastle.asn1.x509.X509Extension;
  import org.bouncycastle.asn1.x509.X509Extensions;
 -import org.bouncycastle.jce.X509LDAPCertStoreParameters;
 +// BEGIN android-removed
@@ -2655,18 +6689,18 @@
  import org.bouncycastle.x509.X509AttributeCertificate;
  import org.bouncycastle.x509.X509CRLStoreSelector;
  import org.bouncycastle.x509.X509CertStoreSelector;
-@@ -250,7 +255,9 @@
+@@ -247,7 +251,9 @@
              {
                  // look for URI
-                 List list = (List) it.next();
+                 List list = (List)it.next();
 -                if (list.get(0).equals(new Integer(GeneralName.uniformResourceIdentifier)))
 +                // BEGIN android-changed
 +                if (list.get(0).equals(Integer.valueOf(GeneralName.uniformResourceIdentifier)))
 +                // END android-changed
                  {
                      // found
-                     String temp = (String) list.get(1);
-@@ -660,38 +667,40 @@
+                     String temp = (String)list.get(1);
+@@ -655,38 +661,40 @@
          {
              try
              {
@@ -2739,13 +6773,13 @@
              }
              catch (Exception e)
              {
-@@ -758,35 +767,37 @@
+@@ -751,33 +759,35 @@
          return certs;
      }
  
 -    protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
 -                                                 List certStores)
--    throws AnnotatedException
+-        throws AnnotatedException
 -    {
 -        Set certs = new HashSet();
 -        Iterator iter = certStores.iterator();
@@ -2763,9 +6797,7 @@
 -                }
 -                catch (StoreException e)
 -                {
--                    throw
--
--                        new AnnotatedException(
+-                    throw new AnnotatedException(
 -                            "Problem while picking certificates from X.509 store.", e);
 -                }
 -            }
@@ -2775,7 +6807,7 @@
 +    // BEGIN android-removed
 +    // protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
 +    //                                              List certStores)
-+    // throws AnnotatedException
++    //     throws AnnotatedException
 +    // {
 +    //     Set certs = new HashSet();
 +    //     Iterator iter = certStores.iterator();
@@ -2793,9 +6825,7 @@
 +    //             }
 +    //             catch (StoreException e)
 +    //             {
-+    //                 throw
-+    //
-+    //                     new AnnotatedException(
++    //                 throw new AnnotatedException(
 +    //                         "Problem while picking certificates from X.509 store.", e);
 +    //             }
 +    //         }
@@ -2806,10 +6836,10 @@
  
      protected static void addAdditionalStoresFromCRLDistributionPoint(
          CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEBlockCipher.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEBlockCipher.java	2012-07-27 18:48:00.031478939 +0000
-@@ -17,8 +17,10 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEBlockCipher.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEBlockCipher.java	2012-09-11 00:12:44.000000000 +0000
+@@ -18,8 +18,10 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.PBEParameterSpec;
@@ -2823,9 +6853,9 @@
  import org.bouncycastle.crypto.BlockCipher;
  import org.bouncycastle.crypto.BufferedBlockCipher;
 @@ -28,7 +30,9 @@
+ import org.bouncycastle.crypto.InvalidCipherTextException;
  import org.bouncycastle.crypto.engines.AESFastEngine;
  import org.bouncycastle.crypto.engines.DESEngine;
- import org.bouncycastle.crypto.engines.DESedeEngine;
 -import org.bouncycastle.crypto.engines.GOST28147Engine;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.engines.GOST28147Engine;
@@ -2833,7 +6863,7 @@
  import org.bouncycastle.crypto.engines.RC2Engine;
  import org.bouncycastle.crypto.engines.TwofishEngine;
  import org.bouncycastle.crypto.modes.AEADBlockCipher;
-@@ -36,12 +40,16 @@
+@@ -36,12 +40,18 @@
  import org.bouncycastle.crypto.modes.CCMBlockCipher;
  import org.bouncycastle.crypto.modes.CFBBlockCipher;
  import org.bouncycastle.crypto.modes.CTSBlockCipher;
@@ -2842,7 +6872,10 @@
 +// import org.bouncycastle.crypto.modes.EAXBlockCipher;
 +// END android-removed
  import org.bouncycastle.crypto.modes.GCMBlockCipher;
- import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+-import org.bouncycastle.crypto.modes.GOFBBlockCipher;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
++// END android-removed
  import org.bouncycastle.crypto.modes.OFBBlockCipher;
 -import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
 -import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
@@ -2853,24 +6886,28 @@
  import org.bouncycastle.crypto.modes.SICBlockCipher;
  import org.bouncycastle.crypto.paddings.BlockCipherPadding;
  import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
-@@ -53,10 +61,12 @@
+@@ -53,12 +63,16 @@
  import org.bouncycastle.crypto.params.KeyParameter;
  import org.bouncycastle.crypto.params.ParametersWithIV;
  import org.bouncycastle.crypto.params.ParametersWithRandom;
 -import org.bouncycastle.crypto.params.ParametersWithSBox;
 -import org.bouncycastle.crypto.params.RC2Parameters;
 -import org.bouncycastle.crypto.params.RC5Parameters;
--import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.params.ParametersWithSBox;
 +// import org.bouncycastle.crypto.params.RC2Parameters;
 +// import org.bouncycastle.crypto.params.RC5Parameters;
++// END android-removed
+ import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+ import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
+-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;
  
- public class JCEBlockCipher extends WrapCipherSpi
-@@ -67,11 +77,15 @@
+@@ -71,11 +85,15 @@
      //
      private Class[]                 availableSpecs =
                                      {
@@ -2889,7 +6926,7 @@
                                      };
   
      private BlockCipher             baseEngine;
-@@ -226,20 +240,22 @@
+@@ -232,20 +250,22 @@
                          new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
              }
          }
@@ -2926,7 +6963,28 @@
          else if (modeName.startsWith("SIC"))
          {
              ivLength = baseEngine.getBlockSize();
-@@ -272,11 +288,13 @@
+@@ -262,12 +282,14 @@
+             cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                         new SICBlockCipher(baseEngine)));
+         }
+-        else if (modeName.startsWith("GOFB"))
+-        {
+-            ivLength = baseEngine.getBlockSize();
+-            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+-                        new GOFBBlockCipher(baseEngine)));
+-        }
++        // BEGIN android-removed
++        // else if (modeName.startsWith("GOFB"))
++        // {
++        //     ivLength = baseEngine.getBlockSize();
++        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
++        //                 new GOFBBlockCipher(baseEngine)));
++        // }
++        // END android-removed
+         else if (modeName.startsWith("CTS"))
+         {
+             ivLength = baseEngine.getBlockSize();
+@@ -278,11 +300,13 @@
              ivLength = baseEngine.getBlockSize();
              cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
          }
@@ -2945,7 +7003,7 @@
          else if (modeName.startsWith("GCM"))
          {
              ivLength = baseEngine.getBlockSize();
-@@ -365,13 +383,15 @@
+@@ -371,13 +395,15 @@
              throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
          }
          
@@ -2968,7 +7026,7 @@
  
          //
          // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
-@@ -437,63 +457,65 @@
+@@ -451,63 +477,65 @@
                  param = new KeyParameter(key.getEncoded());
              }
          }
@@ -3091,7 +7149,7 @@
          else
          {
              throw new InvalidAlgorithmParameterException("unknown parameter type.");
-@@ -697,10 +719,21 @@
+@@ -711,10 +739,21 @@
          int     inputLen,
          byte[]  output,
          int     outputOffset) 
@@ -3114,7 +7172,7 @@
          if (inputLen != 0)
          {
                  len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
-@@ -742,62 +775,64 @@
+@@ -756,62 +795,64 @@
          }
      }
  
@@ -3235,150 +7293,11 @@
  
      /**
       * PBEWithMD5AndDES
-@@ -822,7 +857,7 @@
-             super(new CBCBlockCipher(new RC2Engine()));
-         }
-     }
--
-+    
-     /**
-      * PBEWithSHA1AndDES
-      */
-@@ -870,7 +905,7 @@
-             super(new CBCBlockCipher(new DESedeEngine()));
-         }
-     }
--
-+    
-     /**
-      * PBEWithSHAAnd128BitRC2-CBC
-      */
-@@ -894,7 +929,7 @@
-             super(new CBCBlockCipher(new RC2Engine()));
-         }
-     }
--
-+    
-     /**
-      * PBEWithSHAAndTwofish-CBC
-      */
-@@ -906,7 +941,7 @@
-             super(new CBCBlockCipher(new TwofishEngine()));
-         }
-     }
--
-+    
-     /**
-      * PBEWithAES-CBC
-      */
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2012-07-27 18:48:00.031478939 +0000
-@@ -36,10 +36,12 @@
- 
-     static
-     {
--        Integer i64 = new Integer(64);
--        Integer i192 = new Integer(192);
--        Integer i128 = new Integer(128);
--        Integer i256 = new Integer(256);
-+        // BEGIN android-changed
-+        Integer i64 = Integer.valueOf(64);
-+        Integer i192 = Integer.valueOf(192);
-+        Integer i128 = Integer.valueOf(128);
-+        Integer i256 = Integer.valueOf(256);
-+        // END android-changed
- 
-         algorithms.put("DES", i64);
-         algorithms.put("DESEDE", i192);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDigestUtil.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDigestUtil.java	2012-07-27 18:48:00.031478939 +0000
-@@ -12,7 +12,9 @@
- import org.bouncycastle.crypto.Digest;
- import org.bouncycastle.crypto.digests.MD5Digest;
- 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.SHA256Digest;
- import org.bouncycastle.crypto.digests.SHA384Digest;
- import org.bouncycastle.crypto.digests.SHA512Digest;
-@@ -22,7 +24,9 @@
- {
-     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 +42,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 +67,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);
-@@ -91,10 +99,12 @@
-         {
-             return new MD5Digest();
-         }
--        if (sha224.contains(digestName))
--        {
--            return new SHA224Digest();
--        }
-+        // BEGIN android-removed
-+        // if (sha224.contains(digestName))
-+        // {
-+        //     return new SHA224Digest();
-+        // }
-+        // END android-removed
-         if (sha256.contains(digestName))
-         {
-             return new SHA256Digest();
-@@ -116,7 +126,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-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPrivateKey.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2012-07-27 18:48:00.031478939 +0000
-@@ -20,7 +20,9 @@
- import org.bouncycastle.asn1.DERObject;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -21,7 +21,9 @@
+ import org.bouncycastle.asn1.DERNull;
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
 -import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
@@ -3388,8 +7307,8 @@
  import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-@@ -199,21 +201,23 @@
-             DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+@@ -203,21 +205,23 @@
+             ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
              X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
  
 -            if (ecP == null) // GOST Curve
@@ -3427,30 +7346,30 @@
              {
                  EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
  
-@@ -324,11 +328,13 @@
-             keyStructure = new ECPrivateKeyStructure(this.getS(), params);
-         }
+@@ -331,11 +335,13 @@
  
--        if (algorithm.equals("ECGOST3410"))
--        {
--            info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), keyStructure.getDERObject());
--        }
--        else
-+        // BEGIN android-removed
-+        // if (algorithm.equals("ECGOST3410"))
-+        // {
-+        //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), keyStructure.getDERObject());
-+        // }
-+        // else
-+        // END android-removed
+         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.getDERObject()), keyStructure.getDERObject());
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPublicKey.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPublicKey.java	2012-07-27 18:48:00.031478939 +0000
-@@ -20,8 +20,10 @@
- import org.bouncycastle.asn1.DERObjectIdentifier;
+                 info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEECPublicKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEECPublicKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -19,8 +19,10 @@
+ import org.bouncycastle.asn1.DERNull;
  import org.bouncycastle.asn1.DEROctetString;
  import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
 -import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
@@ -3462,17 +7381,15 @@
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
  import org.bouncycastle.asn1.x9.X962Parameters;
-@@ -31,11 +33,15 @@
- import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
- import org.bouncycastle.crypto.params.ECDomainParameters;
- import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+@@ -33,9 +35,13 @@
+ import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+ import org.bouncycastle.jcajce.provider.asymmetric.ec.ECUtil;
+ import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
 -import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
 +// BEGIN android-removed
 +// import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
 +// END android-removed
  import org.bouncycastle.jce.interfaces.ECPointEncoder;
- import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
- import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
 -import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
 +// BEGIN android-removed
 +// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
@@ -3514,7 +7431,7 @@
 -
 -            try
 -            {
--                key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
+-                key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes());
 -            }
 -            catch (IOException ex)
 -            {
@@ -3563,7 +7480,7 @@
 +        //
 +        //     try
 +        //     {
-+        //         key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
++        //         key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes());
 +        //     }
 +        //     catch (IOException ex)
 +        //     {
@@ -3605,7 +7522,7 @@
 +        // else
 +        // END android-removed
          {
-             X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
+             X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters());
              ECCurve                 curve;
 @@ -315,45 +327,47 @@
          ASN1Encodable        params;
@@ -3647,7 +7564,7 @@
 -            extractBytes(encKey, 0, bX);
 -            extractBytes(encKey, 32, bY);
 -
--            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
+-            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
 -        }
 -        else
 +        // BEGIN android-removed
@@ -3687,281 +7604,47 @@
 +        //     extractBytes(encKey, 0, bX);
 +        //     extractBytes(encKey, 32, bY);
 +        //
-+        //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
++        //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
 +        // }
 +        // else
 +        // END android-removed
          {
              if (ecSpec instanceof ECNamedCurveSpec)
              {
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEKeyGenerator.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2012-07-27 18:48:00.031478939 +0000
-@@ -57,6 +57,11 @@
-     {
-         try
-         {
-+            // BEGIN android-added
-+            if (random == null) {
-+                random = new SecureRandom();
-+            }
-+            // END android-added
-             engine.init(new KeyGenerationParameters(random, keySize));
-             uninitialised = false;
-         }
-@@ -93,56 +98,60 @@
-         }
-     }
- 
--    /**
--     * RC2
--     */
--    public static class RC2
--        extends JCEKeyGenerator
--    {
--        public RC2()
--        {
--            super("RC2", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * GOST28147
--     */
--    public static class GOST28147
--        extends JCEKeyGenerator
--    {
--        public GOST28147()
--        {
--            super("GOST28147", 256, new CipherKeyGenerator());
--        }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * RC2
-+    //  */
-+    // public static class RC2
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public RC2()
-+    //     {
-+    //         super("RC2", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * GOST28147
-+    //  */
-+    // public static class GOST28147
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public GOST28147()
-+    //     {
-+    //         super("GOST28147", 256, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    // END android-removed
- 
-     // HMAC Related secret keys..
-   
--    /**
--     * MD2HMAC
--     */
--    public static class MD2HMAC
--        extends JCEKeyGenerator
--    {
--        public MD2HMAC()
--        {
--            super("HMACMD2", 128, new CipherKeyGenerator());
--        }
--    }
--
--
--    /**
--     * MD4HMAC
--     */
--    public static class MD4HMAC
--        extends JCEKeyGenerator
--    {
--        public MD4HMAC()
--        {
--            super("HMACMD4", 128, new CipherKeyGenerator());
--        }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * MD2HMAC
-+    //  */
-+    // public static class MD2HMAC
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public MD2HMAC()
-+    //     {
-+    //         super("HMACMD2", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    //
-+    // /**
-+    //  * MD4HMAC
-+    //  */
-+    // public static class MD4HMAC
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public MD4HMAC()
-+    //     {
-+    //         super("HMACMD4", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    // END android-removed
- 
-     /**
-      * MD5HMAC
-@@ -157,29 +166,29 @@
-     }
- 
- 
--    /**
--     * RIPE128HMAC
--     */
--    public static class RIPEMD128HMAC
--        extends JCEKeyGenerator
--    {
--        public RIPEMD128HMAC()
--        {
--            super("HMACRIPEMD128", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * RIPE160HMAC
--     */
--    public static class RIPEMD160HMAC
--        extends JCEKeyGenerator
--    {
--        public RIPEMD160HMAC()
--        {
--            super("HMACRIPEMD160", 160, new CipherKeyGenerator());
--        }
--    }
-+    // /**
-+    //  * RIPE128HMAC
-+    //  */
-+    // public static class RIPEMD128HMAC
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public RIPEMD128HMAC()
-+    //     {
-+    //         super("HMACRIPEMD128", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+
-+    // /**
-+    //  * RIPE160HMAC
-+    //  */
-+    // public static class RIPEMD160HMAC
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public RIPEMD160HMAC()
-+    //     {
-+    //         super("HMACRIPEMD160", 160, new CipherKeyGenerator());
-+    //     }
-+    // }
- 
- 
-     /**
-@@ -194,17 +203,19 @@
-         }
-     }
- 
--    /**
--     * HMACSHA224
--     */
--    public static class HMACSHA224
--        extends JCEKeyGenerator
--    {
--        public HMACSHA224()
--        {
--            super("HMACSHA224", 224, new CipherKeyGenerator());
--        }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * HMACSHA224
-+    //  */
-+    // public static class HMACSHA224
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public HMACSHA224()
-+    //     {
-+    //         super("HMACSHA224", 224, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    // END android-removed
-     
-     /**
-      * HMACSHA256
-@@ -242,15 +253,17 @@
-         }
-     }
-     
--    /**
--     * HMACTIGER
--     */
--    public static class HMACTIGER
--        extends JCEKeyGenerator
--    {
--        public HMACTIGER()
--        {
--            super("HMACTIGER", 192, new CipherKeyGenerator());
--        }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * HMACTIGER
-+    //  */
-+    // public static class HMACTIGER
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public HMACTIGER()
-+    //     {
-+    //         super("HMACTIGER", 192, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEMac.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEMac.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEMac.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEMac.java	2012-07-27 18:48:00.031478939 +0000
-@@ -11,25 +11,39 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEMac.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEMac.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEMac.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEMac.java	2012-09-11 00:12:44.000000000 +0000
+@@ -11,24 +11,35 @@
  
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Mac;
 -import org.bouncycastle.crypto.digests.MD2Digest;
 -import org.bouncycastle.crypto.digests.MD4Digest;
+-import org.bouncycastle.crypto.digests.MD5Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+-import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
+-import org.bouncycastle.crypto.digests.SHA256Digest;
+-import org.bouncycastle.crypto.digests.SHA384Digest;
+-import org.bouncycastle.crypto.digests.SHA512Digest;
+-import org.bouncycastle.crypto.digests.TigerDigest;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.digests.MD2Digest;
 +// import org.bouncycastle.crypto.digests.MD4Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.MD5Digest;
--import org.bouncycastle.crypto.digests.RIPEMD128Digest;
--import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.MD5Digest;
 +// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
 +// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.SHA1Digest;
--import org.bouncycastle.crypto.digests.SHA224Digest;
-+// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.SHA1Digest;
 +// import org.bouncycastle.crypto.digests.SHA224Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.SHA256Digest;
- import org.bouncycastle.crypto.digests.SHA384Digest;
- import org.bouncycastle.crypto.digests.SHA512Digest;
--import org.bouncycastle.crypto.digests.TigerDigest;
-+// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.SHA256Digest;
++// import org.bouncycastle.crypto.digests.SHA384Digest;
++// import org.bouncycastle.crypto.digests.SHA512Digest;
 +// import org.bouncycastle.crypto.digests.TigerDigest;
 +// END android-removed
++// BEGIN android-added
++import org.bouncycastle.crypto.digests.OpenSSLDigest;
++// END android-added
  import org.bouncycastle.crypto.engines.DESEngine;
 -import org.bouncycastle.crypto.engines.RC2Engine;
 +// BEGIN android-removed
@@ -3969,10 +7652,8 @@
 +// END android-removed
  import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
 -import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
--import org.bouncycastle.crypto.macs.GOST28147Mac;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
-+// import org.bouncycastle.crypto.macs.GOST28147Mac;
 +// END android-removed
  import org.bouncycastle.crypto.macs.HMac;
 -import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
@@ -3984,7 +7665,7 @@
  import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
  import org.bouncycastle.crypto.params.KeyParameter;
  import org.bouncycastle.crypto.params.ParametersWithIV;
-@@ -143,115 +157,117 @@
+@@ -144,109 +155,111 @@
       * the classes that extend directly off us.
       */
  
@@ -4001,6 +7682,18 @@
 -    }
 -
 -    /**
+-     * DES 64 bit MAC
+-     */
+-    public static class DES64
+-        extends JCEMac
+-    {
+-        public DES64()
+-        {
+-            super(new CBCBlockCipherMac(new DESEngine(), 64));
+-        }
+-    }
+-
+-    /**
 -     * RC2
 -     */
 -    public static class RC2
@@ -4012,17 +7705,6 @@
 -        }
 -    }
 -
--    /**
--     * GOST28147
--     */
--    public static class GOST28147
--        extends JCEMac
--    {
--        public GOST28147()
--        {
--            super(new GOST28147Mac());
--        }
--    }
 -
 -    
 -
@@ -4041,14 +7723,7 @@
 -    /**
 -     * RC2CFB8
 -     */
--    public static class RC2CFB8
--        extends JCEMac
--    {
--        public RC2CFB8()
--        {
--            super(new CFBBlockCipherMac(new RC2Engine()));
--        }
--    }
+-
 -
 -    /**
 -     * DES9797Alg3with7816-4Padding
@@ -4111,6 +7786,18 @@
 +    // }
 +    //
 +    // /**
++    //  * DES 64 bit MAC
++    //  */
++    // public static class DES64
++    //     extends JCEMac
++    // {
++    //     public DES64()
++    //     {
++    //         super(new CBCBlockCipherMac(new DESEngine(), 64));
++    //     }
++    // }
++    //
++    // /**
 +    //  * RC2
 +    //  */
 +    // public static class RC2
@@ -4122,17 +7809,6 @@
 +    //     }
 +    // }
 +    //
-+    // /**
-+    //  * GOST28147
-+    //  */
-+    // public static class GOST28147
-+    //     extends JCEMac
-+    // {
-+    //     public GOST28147()
-+    //     {
-+    //         super(new GOST28147Mac());
-+    //     }
-+    // }
 +    //
 +    //
 +    //
@@ -4151,14 +7827,7 @@
 +    // /**
 +    //  * RC2CFB8
 +    //  */
-+    // public static class RC2CFB8
-+    //     extends JCEMac
-+    // {
-+    //     public RC2CFB8()
-+    //     {
-+    //         super(new CFBBlockCipherMac(new RC2Engine()));
-+    //     }
-+    // }
++    //
 +    //
 +    // /**
 +    //  * DES9797Alg3with7816-4Padding
@@ -4211,20 +7880,28 @@
  
      /**
       * MD5 HMac
-@@ -264,7 +280,7 @@
-             super(new HMac(new MD5Digest()));
+@@ -256,7 +269,9 @@
+     {
+         public MD5()
+         {
+-            super(new HMac(new MD5Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.MD5()));
++            // END android-changed
          }
      }
--
-+    
-     /**
-      * SHA1 HMac
-      */
-@@ -276,18 +292,20 @@
-             super(new HMac(new SHA1Digest()));
+ 
+@@ -268,21 +283,25 @@
+     {
+         public SHA1()
+         {
+-            super(new HMac(new SHA1Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA1()));
++            // END android-changed
          }
      }
--
+ 
 -    /**
 -     * SHA-224 HMac
 -     */
@@ -4236,7 +7913,6 @@
 -            super(new HMac(new SHA224Digest()));
 -        }
 -    }
-+    
 +    // BEGIN android-removed
 +    // /**
 +    //  * SHA-224 HMac
@@ -4253,20 +7929,28 @@
      
      /**
       * SHA-256 HMac
-@@ -300,7 +318,7 @@
-             super(new HMac(new SHA256Digest()));
+@@ -292,7 +311,9 @@
+     {
+         public SHA256()
+         {
+-            super(new HMac(new SHA256Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA256()));
++            // END android-changed
          }
      }
--
-+    
-     /**
-      * SHA-384 HMac
-      */
-@@ -312,15 +330,17 @@
-             super(new HMac(new SHA384Digest()));
+ 
+@@ -304,18 +325,22 @@
+     {
+         public SHA384()
+         {
+-            super(new HMac(new SHA384Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA384()));
++            // END android-changed
          }
      }
--
+ 
 -    public static class OldSHA384
 -        extends JCEMac
 -    {
@@ -4275,7 +7959,6 @@
 -            super(new OldHMac(new SHA384Digest()));
 -        }
 -    }
-+    
 +    // BEGIN android-removed
 +    // public static class OldSHA384
 +    //     extends JCEMac
@@ -4289,11 +7972,17 @@
      
      /**
       * SHA-512 HMac
-@@ -333,73 +353,75 @@
-             super(new HMac(new SHA512Digest()));
+@@ -325,75 +350,80 @@
+     {
+         public SHA512()
+         {
+-            super(new HMac(new SHA512Digest()));
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA512()));
++            // END android-changed
          }
      }
--
+ 
 -    /**
 -     * SHA-512 HMac
 -     */
@@ -4382,7 +8071,6 @@
 -            super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
 -        }
 -    }
--
 +    // /**
 +    //  * RIPEMD160 HMac
 +    //  */
@@ -4425,15 +8113,20 @@
 +    //     }
 +    // }
 +    // END android-removed
-+    
+ 
      /**
       * PBEWithHmacSHA
-      */
-@@ -411,16 +433,18 @@
-             super(new HMac(new SHA1Digest()), PKCS12, SHA1, 160);
+@@ -403,19 +433,23 @@
+     {
+         public PBEWithSHA()
+         {
+-            super(new HMac(new SHA1Digest()), PKCS12, SHA1, 160);
++            // BEGIN android-changed
++            super(new HMac(new OpenSSLDigest.SHA1()), PKCS12, SHA1, 160);
++            // END android-changed
          }
      }
--
+ 
 -    /**
 -     * PBEWithHmacTiger
 -     */
@@ -4445,7 +8138,6 @@
 -            super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
 -        }
 -    }
-+    
 +    // BEGIN android-removed
 +    //  /**
 +    //   * PBEWithHmacTiger
@@ -4460,150 +8152,52 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSACipher.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSACipher.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSACipher.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSACipher.java	2012-07-27 18:48:00.031478939 +0000
-@@ -535,48 +535,50 @@
-         }
-     }
- 
--    static public class PKCS1v1_5Padding
--        extends JCERSACipher
--    {
--        public PKCS1v1_5Padding()
--        {
--            super(new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class PKCS1v1_5Padding_PrivateOnly
--        extends JCERSACipher
--    {
--        public PKCS1v1_5Padding_PrivateOnly()
--        {
--            super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class PKCS1v1_5Padding_PublicOnly
--        extends JCERSACipher
--    {
--        public PKCS1v1_5Padding_PublicOnly()
--        {
--            super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class OAEPPadding
--        extends JCERSACipher
--    {
--        public OAEPPadding()
--        {
--            super(OAEPParameterSpec.DEFAULT);
--        }
--    }
--    
--    static public class ISO9796d1Padding
--        extends JCERSACipher
--    {
--        public ISO9796d1Padding()
--        {
--            super(new ISO9796d1Encoding(new RSABlindedEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class PKCS1v1_5Padding
-+    //     extends JCERSACipher
-+    // {
-+    //     public PKCS1v1_5Padding()
-+    //     {
-+    //         super(new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class PKCS1v1_5Padding_PrivateOnly
-+    //     extends JCERSACipher
-+    // {
-+    //     public PKCS1v1_5Padding_PrivateOnly()
-+    //     {
-+    //         super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class PKCS1v1_5Padding_PublicOnly
-+    //     extends JCERSACipher
-+    // {
-+    //     public PKCS1v1_5Padding_PublicOnly()
-+    //     {
-+    //         super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class OAEPPadding
-+    //     extends JCERSACipher
-+    // {
-+    //     public OAEPPadding()
-+    //     {
-+    //         super(OAEPParameterSpec.DEFAULT);
-+    //     }
-+    // }
-+    //
-+    // static public class ISO9796d1Padding
-+    //     extends JCERSACipher
-+    // {
-+    //     public ISO9796d1Padding()
-+    //     {
-+    //         super(new ISO9796d1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2012-07-27 18:48:00.031478939 +0000
-@@ -125,7 +125,9 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -127,7 +127,9 @@
       */
      public byte[] getEncoded()
      {
--        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new RSAPrivateKeyStructure(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()).getDERObject());
+-        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
 +        // BEGIN android-changed
-+        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKeyStructure(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()).getDERObject());
++        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
 +        // END android-changed
- 
-         return info.getDEREncoded();
      }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2012-07-27 18:48:00.031478939 +0000
-@@ -77,7 +77,9 @@
+ 
+     /**
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -78,7 +78,9 @@
  
      public byte[] getEncoded()
      {
--        PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new RSAPrivateKeyStructure(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO).getDERObject());
+-        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
 +        // BEGIN android-changed
-+        PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKeyStructure(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO).getDERObject());
++        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
 +        // END android-changed
- 
-         return info.getDEREncoded();
      }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPublicKey.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2012-07-27 18:48:00.031478939 +0000
-@@ -90,7 +90,9 @@
+ 
+     public boolean equals(Object o)
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCERSAPublicKey.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2012-09-11 00:12:44.000000000 +0000
+@@ -91,7 +91,9 @@
  
      public byte[] getEncoded()
      {
--        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new RSAPublicKeyStructure(getModulus(), getPublicExponent()).getDERObject());
+-        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, new DERNull()), new RSAPublicKeyStructure(getModulus(), getPublicExponent()));
 +        // BEGIN android-changed
-+        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()).getDERObject());
++        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()));
 +        // END android-changed
- 
-         return info.getDEREncoded();
      }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2012-07-27 18:48:00.031478939 +0000
-@@ -250,29 +250,31 @@
+ 
+     public int hashCode()
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2012-09-11 00:12:44.000000000 +0000
+@@ -252,29 +252,31 @@
          }
      }
  
@@ -4658,7 +8252,7 @@
  
     /**
      * PBEWithMD5AndDES
-@@ -406,17 +408,19 @@
+@@ -408,17 +410,19 @@
         }
     }
     
@@ -4689,7 +8283,7 @@
  
     /**
      * PBEWithHmacSHA
-@@ -430,17 +434,19 @@
+@@ -432,17 +436,19 @@
         }
     }
  
@@ -4720,7 +8314,7 @@
     
     /**
      * PBEWithSHA1And128BitAES-BC
-@@ -549,4 +555,56 @@
+@@ -551,4 +557,56 @@
             super("PBEWithMD5And256BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
         }
     }
@@ -4769,7 +8363,7 @@
 +                int ivSize = -1;
 +                CipherParameters param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
 +                
-+                return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
++                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
 +            }
 +            
 +            throw new InvalidKeySpecException("Invalid KeySpec");
@@ -4777,10 +8371,10 @@
 +    }
 +    // END android-added
  }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEStreamCipher.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEStreamCipher.java	2012-07-27 18:48:00.041479127 +0000
-@@ -13,20 +13,26 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEStreamCipher.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEStreamCipher.java	2012-09-11 00:12:44.000000000 +0000
+@@ -14,20 +14,26 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.PBEParameterSpec;
@@ -4814,7 +8408,7 @@
  import org.bouncycastle.crypto.modes.CFBBlockCipher;
  import org.bouncycastle.crypto.modes.OFBBlockCipher;
  import org.bouncycastle.crypto.params.KeyParameter;
-@@ -40,8 +46,10 @@
+@@ -44,8 +50,10 @@
      //
      private Class[]                 availableSpecs =
                                      {
@@ -4827,7 +8421,7 @@
                                          IvParameterSpec.class,
                                          PBEParameterSpec.class
                                      };
-@@ -370,125 +378,127 @@
+@@ -376,125 +384,127 @@
       * The ciphers that inherit from us.
       */
  
@@ -5074,1262 +8668,24 @@
  
      /**
       * PBEWithSHAAnd128BitRC4
-@@ -501,7 +511,7 @@
-             super(new RC4Engine(), 0);
-         }
-     }
--
-+    
-     /**
-      * PBEWithSHAAnd40BitRC4
-      */
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2012-07-27 18:48:00.031478939 +0000
-@@ -11,18 +11,24 @@
- import javax.crypto.spec.DHGenParameterSpec;
- import javax.crypto.spec.DHParameterSpec;
- import javax.crypto.spec.IvParameterSpec;
--import javax.crypto.spec.RC2ParameterSpec;
-+// BEGIN android-removed
-+// import javax.crypto.spec.RC2ParameterSpec;
-+// END android-removed
- 
- import org.bouncycastle.crypto.generators.DHParametersGenerator;
- import org.bouncycastle.crypto.generators.DSAParametersGenerator;
--import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
--import org.bouncycastle.crypto.generators.GOST3410ParametersGenerator;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
-+// import org.bouncycastle.crypto.generators.GOST3410ParametersGenerator;
-+// END android-removed
- import org.bouncycastle.crypto.params.DHParameters;
- import org.bouncycastle.crypto.params.DSAParameters;
--import org.bouncycastle.crypto.params.ElGamalParameters;
--import org.bouncycastle.crypto.params.GOST3410Parameters;
--import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
--import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.params.ElGamalParameters;
-+// import org.bouncycastle.crypto.params.GOST3410Parameters;
-+// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-+// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-+// END android-removed
- 
- public abstract class JDKAlgorithmParameterGenerator
-     extends AlgorithmParameterGeneratorSpi
-@@ -145,196 +151,198 @@
-         }
-     }
- 
--    public static class GOST3410
--        extends JDKAlgorithmParameterGenerator
--    {
--        protected void engineInit(
--                AlgorithmParameterSpec  genParamSpec,
--                SecureRandom            random)
--        throws InvalidAlgorithmParameterException
--        {
--            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
--        }
--        
--        protected AlgorithmParameters engineGenerateParameters()
--        {
--            GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
--            
--            if (random != null)
--            {
--                pGen.init(strength, 2, random);
--            }
--            else
--            {
--                pGen.init(strength, 2, new SecureRandom());
--            }
--            
--            GOST3410Parameters p = pGen.generateParameters();
--            
--            AlgorithmParameters params;
--            
--            try
--            {
--                params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
--                params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
--            }
--            catch (Exception e)
--            {
--                throw new RuntimeException(e.getMessage());
--            }
--            
--            return params;
--        }
--    }
--    
--    public static class ElGamal
--        extends JDKAlgorithmParameterGenerator
--    {
--        private int l = 0;
--        
--        protected void engineInit(
--            AlgorithmParameterSpec  genParamSpec,
--            SecureRandom            random)
--            throws InvalidAlgorithmParameterException
--        {
--            if (!(genParamSpec instanceof DHGenParameterSpec))
--            {
--                throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
--            }
--            DHGenParameterSpec  spec = (DHGenParameterSpec)genParamSpec;
--
--            this.strength = spec.getPrimeSize();
--            this.l = spec.getExponentSize();
--            this.random = random;
--        }
--
--        protected AlgorithmParameters engineGenerateParameters()
--        {
--            ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
--
--            if (random != null)
--            {
--                pGen.init(strength, 20, random);
--            }
--            else
--            {
--                pGen.init(strength, 20, new SecureRandom());
--            }
--
--            ElGamalParameters p = pGen.generateParameters();
--
--            AlgorithmParameters params;
--
--            try
--            {
--                params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
--                params.init(new DHParameterSpec(p.getP(), p.getG(), l));
--            }
--            catch (Exception e)
--            {
--                throw new RuntimeException(e.getMessage());
--            }
--
--            return params;
--        }
--    }
--
--    public static class DES
--        extends JDKAlgorithmParameterGenerator
--    {
--        protected void engineInit(
--            AlgorithmParameterSpec  genParamSpec,
--            SecureRandom            random)
--            throws InvalidAlgorithmParameterException
--        {
--            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
--        }
--
--        protected AlgorithmParameters engineGenerateParameters()
--        {
--            byte[]  iv = new byte[8];
--
--            if (random == null)
--            {
--                random = new SecureRandom();
--            }
--
--            random.nextBytes(iv);
--
--            AlgorithmParameters params;
--
--            try
--            {
--                params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
--                params.init(new IvParameterSpec(iv));
--            }
--            catch (Exception e)
--            {
--                throw new RuntimeException(e.getMessage());
--            }
--
--            return params;
--        }
--    }
--
--    public static class RC2
--        extends JDKAlgorithmParameterGenerator
--    {
--        RC2ParameterSpec    spec = null;
--
--        protected void engineInit(
--            AlgorithmParameterSpec  genParamSpec,
--            SecureRandom            random)
--            throws InvalidAlgorithmParameterException
--        {
--            if (genParamSpec instanceof RC2ParameterSpec)
--            {
--                spec = (RC2ParameterSpec)genParamSpec;
--                return;
--            }
--
--            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
--        }
--
--        protected AlgorithmParameters engineGenerateParameters()
--        {
--            AlgorithmParameters params;
--
--            if (spec == null)
--            {
--                byte[]  iv = new byte[8];
--
--                if (random == null)
--                {
--                    random = new SecureRandom();
--                }
--
--                random.nextBytes(iv);
--
--                try
--                {
--                    params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
--                    params.init(new IvParameterSpec(iv));
--                }
--                catch (Exception e)
--                {
--                    throw new RuntimeException(e.getMessage());
--                }
--            }
--            else
--            {
--                try
--                {
--                    params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
--                    params.init(spec);
--                }
--                catch (Exception e)
--                {
--                    throw new RuntimeException(e.getMessage());
--                }
--            }
--
--            return params;
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class GOST3410
-+    //     extends JDKAlgorithmParameterGenerator
-+    // {
-+    //     protected void engineInit(
-+    //             AlgorithmParameterSpec  genParamSpec,
-+    //             SecureRandom            random)
-+    //     throws InvalidAlgorithmParameterException
-+    //     {
-+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
-+    //     }
-+    //    
-+    //     protected AlgorithmParameters engineGenerateParameters()
-+    //     {
-+    //         GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
-+    //        
-+    //         if (random != null)
-+    //         {
-+    //             pGen.init(strength, 2, random);
-+    //         }
-+    //         else
-+    //         {
-+    //             pGen.init(strength, 2, new SecureRandom());
-+    //         }
-+    //        
-+    //         GOST3410Parameters p = pGen.generateParameters();
-+    //        
-+    //         AlgorithmParameters params;
-+    //
-+    //         try
-+    //         {
-+    //             params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
-+    //             params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
-+    //         }
-+    //         catch (Exception e)
-+    //         {
-+    //             throw new RuntimeException(e.getMessage());
-+    //         }
-+    //
-+    //         return params;
-+    //     }
-+    // }
-+    //
-+    // public static class ElGamal
-+    //     extends JDKAlgorithmParameterGenerator
-+    // {
-+    //     private int l = 0;
-+    //
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec  genParamSpec,
-+    //         SecureRandom            random)
-+    //         throws InvalidAlgorithmParameterException
-+    //     {
-+    //         if (!(genParamSpec instanceof DHGenParameterSpec))
-+    //         {
-+    //             throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
-+    //         }
-+    //         DHGenParameterSpec  spec = (DHGenParameterSpec)genParamSpec;
-+    //
-+    //         this.strength = spec.getPrimeSize();
-+    //         this.l = spec.getExponentSize();
-+    //         this.random = random;
-+    //     }
-+    //
-+    //     protected AlgorithmParameters engineGenerateParameters()
-+    //     {
-+    //         ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
-+    //
-+    //         if (random != null)
-+    //         {
-+    //             pGen.init(strength, 20, random);
-+    //         }
-+    //         else
-+    //         {
-+    //             pGen.init(strength, 20, new SecureRandom());
-+    //         }
-+    //
-+    //         ElGamalParameters p = pGen.generateParameters();
-+    //
-+    //         AlgorithmParameters params;
-+    //
-+    //         try
-+    //         {
-+    //             params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
-+    //             params.init(new DHParameterSpec(p.getP(), p.getG(), l));
-+    //         }
-+    //         catch (Exception e)
-+    //         {
-+    //             throw new RuntimeException(e.getMessage());
-+    //         }
-+    //
-+    //         return params;
-+    //     }
-+    // }
-+    //
-+    // public static class DES
-+    //     extends JDKAlgorithmParameterGenerator
-+    // {
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec  genParamSpec,
-+    //         SecureRandom            random)
-+    //         throws InvalidAlgorithmParameterException
-+    //     {
-+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
-+    //     }
-+    //
-+    //     protected AlgorithmParameters engineGenerateParameters()
-+    //     {
-+    //         byte[]  iv = new byte[8];
-+    //
-+    //         if (random == null)
-+    //         {
-+    //             random = new SecureRandom();
-+    //         }
-+    //
-+    //         random.nextBytes(iv);
-+    //
-+    //         AlgorithmParameters params;
-+    //
-+    //         try
-+    //         {
-+    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
-+    //             params.init(new IvParameterSpec(iv));
-+    //         }
-+    //         catch (Exception e)
-+    //         {
-+    //             throw new RuntimeException(e.getMessage());
-+    //         }
-+    //
-+    //         return params;
-+    //     }
-+    // }
-+    //
-+    // public static class RC2
-+    //     extends JDKAlgorithmParameterGenerator
-+    // {
-+    //     RC2ParameterSpec    spec = null;
-+    //
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec  genParamSpec,
-+    //         SecureRandom            random)
-+    //         throws InvalidAlgorithmParameterException
-+    //     {
-+    //         if (genParamSpec instanceof RC2ParameterSpec)
-+    //         {
-+    //             spec = (RC2ParameterSpec)genParamSpec;
-+    //             return;
-+    //         }
-+    //
-+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
-+    //     }
-+    //
-+    //     protected AlgorithmParameters engineGenerateParameters()
-+    //     {
-+    //         AlgorithmParameters params;
-+    //
-+    //         if (spec == null)
-+    //         {
-+    //             byte[]  iv = new byte[8];
-+    //
-+    //             if (random == null)
-+    //             {
-+    //                 random = new SecureRandom();
-+    //             }
-+    //
-+    //             random.nextBytes(iv);
-+    //
-+    //             try
-+    //             {
-+    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
-+    //                 params.init(new IvParameterSpec(iv));
-+    //             }
-+    //             catch (Exception e)
-+    //             {
-+    //                 throw new RuntimeException(e.getMessage());
-+    //             }
-+    //         }
-+    //         else
-+    //         {
-+    //             try
-+    //             {
-+    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
-+    //                 params.init(spec);
-+    //             }
-+    //             catch (Exception e)
-+    //             {
-+    //                 throw new RuntimeException(e.getMessage());
-+    //             }
-+    //         }
-+    //
-+    //         return params;
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2012-07-27 18:48:00.031478939 +0000
-@@ -10,21 +10,27 @@
- import org.bouncycastle.asn1.DERObjectIdentifier;
- import org.bouncycastle.asn1.DEROctetString;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2012-09-11 00:12:44.000000000 +0000
+@@ -17,7 +17,9 @@
  import org.bouncycastle.asn1.DERSequence;
--import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
--import org.bouncycastle.asn1.oiw.ElGamalParameter;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
-+// END android-removed
- import org.bouncycastle.asn1.pkcs.DHParameter;
- import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
- import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
--import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
-+// END android-removed
- import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
- import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
  import org.bouncycastle.asn1.pkcs.PBKDF2Params;
- import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
- import org.bouncycastle.asn1.x509.DSAParameter;
--import org.bouncycastle.jce.spec.ElGamalParameterSpec;
--import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
--import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+ import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
 -import org.bouncycastle.jce.spec.IESParameterSpec;
 +// BEGIN android-removed
-+// import org.bouncycastle.jce.spec.ElGamalParameterSpec;
-+// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-+// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
 +// import org.bouncycastle.jce.spec.IESParameterSpec;
 +// END android-removed
- import org.bouncycastle.util.Arrays;
  
- import javax.crypto.spec.DHParameterSpec;
-@@ -32,7 +38,9 @@
- import javax.crypto.spec.OAEPParameterSpec;
- import javax.crypto.spec.PBEParameterSpec;
- import javax.crypto.spec.PSource;
--import javax.crypto.spec.RC2ParameterSpec;
-+// BEGIN android-removed
-+// import javax.crypto.spec.RC2ParameterSpec;
-+// END android-removed
- import java.io.IOException;
- import java.security.AlgorithmParametersSpi;
- import java.security.spec.AlgorithmParameterSpec;
-@@ -68,13 +76,13 @@
-         extends JDKAlgorithmParameters
-     {
-         private byte[]  iv;
--
-+    
-         protected byte[] engineGetEncoded() 
-             throws IOException
-         {
-             return engineGetEncoded("ASN.1");
-         }
--
-+    
-         protected byte[] engineGetEncoded(
-             String format) 
-             throws IOException
-@@ -83,15 +91,15 @@
-             {
-                  return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
-             }
--            
-+    
-             if (format.equals("RAW"))
-             {
-                 return Arrays.clone(iv);
-             }
--
-+    
-             return null;
-         }
--
-+    
-         protected AlgorithmParameterSpec localEngineGetParameterSpec(
-             Class paramSpec) 
-             throws InvalidParameterSpecException
-@@ -100,10 +108,10 @@
-             {
-                 return new IvParameterSpec(iv);
-             }
--
-+    
-             throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
-         }
--
-+    
-         protected void engineInit(
-             AlgorithmParameterSpec paramSpec) 
-             throws InvalidParameterSpecException
-@@ -112,10 +120,10 @@
-             {
-                 throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
-             }
--
-+    
-             this.iv = ((IvParameterSpec)paramSpec).getIV();
-         }
--
-+    
-         protected void engineInit(
-             byte[] params) 
-             throws IOException
-@@ -127,13 +135,13 @@
-                     && params[0] == 0x04 && params[1] == params.length - 2)
-             {
-                 ASN1OctetString oct = (ASN1OctetString)ASN1Object.fromByteArray(params);
--
-+    
-                 params = oct.getOctets();
-             }
--
-+    
-             this.iv = Arrays.clone(params);
-         }
--
-+    
-         protected void engineInit(
-             byte[] params,
-             String format) 
-@@ -144,204 +152,206 @@
-                 try
-                 {
-                     ASN1OctetString oct = (ASN1OctetString)ASN1Object.fromByteArray(params);
--
-+    
-                     engineInit(oct.getOctets());
-                 }
-                 catch (Exception e)
-                 {
-                     throw new IOException("Exception decoding: " + e);
-                 }
--                
-+    
-                 return;
-             }
--
-+    
-             if (format.equals("RAW"))
-             {
-                 engineInit(params);
-                 return;
-             }
--
-+    
-             throw new IOException("Unknown parameters format in IV parameters object");
-         }
--
-+    
-         protected String engineToString() 
-         {
-             return "IV Parameters";
+ public abstract class JDKAlgorithmParameters
+     extends AlgorithmParametersSpi
+@@ -208,109 +210,111 @@
          }
      }
--
--    public static class RC2AlgorithmParameters
--        extends JDKAlgorithmParameters
--    {
--        private static final short[] table = {
--           0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
--           0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
--           0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
--           0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
--           0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
--           0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
--           0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
--           0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
--           0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
--           0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
--           0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
--           0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
--           0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
--           0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
--           0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
--           0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
--        };
--
--        private static final short[] ekb = {
--           0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
--           0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
--           0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
--           0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
--           0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
--           0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
--           0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
--           0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
--           0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
--           0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
--           0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
--           0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
--           0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
--           0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
--           0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
--           0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
--        };
--
--        private byte[]  iv;
--        private int     parameterVersion = 58;
--
--        protected byte[] engineGetEncoded() 
--        {
--            return Arrays.clone(iv);
--        }
--
--        protected byte[] engineGetEncoded(
--            String format) 
--            throws IOException
--        {
--            if (isASN1FormatString(format))
--            {
--                if (parameterVersion == -1)
--                {
--                    return new RC2CBCParameter(engineGetEncoded()).getEncoded();
--                }
--                else
--                {
--                    return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
--                }
--            }
--
--            if (format.equals("RAW"))
--            {
--                return engineGetEncoded();
--            }
--
--            return null;
--        }
--
--        protected AlgorithmParameterSpec localEngineGetParameterSpec(
--            Class paramSpec) 
--            throws InvalidParameterSpecException
--        {
--            if (paramSpec == RC2ParameterSpec.class)
--            {
--                if (parameterVersion != -1)
--                {
--                    if (parameterVersion < 256)
--                    {
--                        return new RC2ParameterSpec(ekb[parameterVersion], iv);
--                    }
--                    else
--                    {
--                        return new RC2ParameterSpec(parameterVersion, iv);
--                    }
--                }
--            }
--
--            if (paramSpec == IvParameterSpec.class)
--            {
--                return new IvParameterSpec(iv);
--            }
--
--            throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
--        }
--
--        protected void engineInit(
--            AlgorithmParameterSpec paramSpec) 
--            throws InvalidParameterSpecException
--        {
--            if (paramSpec instanceof IvParameterSpec)
--            {
--                this.iv = ((IvParameterSpec)paramSpec).getIV();
--            }
--            else if (paramSpec instanceof RC2ParameterSpec)
--            {
--                int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
--                if (effKeyBits != -1)
--                {
--                    if (effKeyBits < 256)
--                    {
--                        parameterVersion = table[effKeyBits];
--                    }
--                    else
--                    {
--                        parameterVersion = effKeyBits;
--                    }
--                }
--
--                this.iv = ((RC2ParameterSpec)paramSpec).getIV();
--            }
--            else
--            {
--                throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
--            }
--        }
--
--        protected void engineInit(
--            byte[] params) 
--            throws IOException
--        {
--            this.iv = Arrays.clone(params);
--        }
--
--        protected void engineInit(
--            byte[] params,
--            String format) 
--            throws IOException
--        {
--            if (isASN1FormatString(format))
--            {
--                RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Object.fromByteArray(params));
--
--                if (p.getRC2ParameterVersion() != null)
--                {
--                    parameterVersion = p.getRC2ParameterVersion().intValue();
--                }
--
--                iv = p.getIV();
--
--                return;
--            }
--
--            if (format.equals("RAW"))
--            {
--                engineInit(params);
--                return;
--            }
--
--            throw new IOException("Unknown parameters format in IV parameters object");
--        }
--
--        protected String engineToString() 
--        {
--            return "RC2 Parameters";
--        }
--    }
--
-+    
-+    // BEGIN android-removed
-+    // public static class RC2AlgorithmParameters
-+    //     extends JDKAlgorithmParameters
-+    // {
-+    //     private static final short[] table = {
-+    //        0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
-+    //        0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
-+    //        0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
-+    //        0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
-+    //        0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
-+    //        0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
-+    //        0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
-+    //        0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
-+    //        0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
-+    //        0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
-+    //        0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
-+    //        0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
-+    //        0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
-+    //        0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
-+    //        0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
-+    //        0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
-+    //     };
-+    //
-+    //     private static final short[] ekb = {
-+    //        0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
-+    //        0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
-+    //        0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
-+    //        0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
-+    //        0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
-+    //        0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
-+    //        0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
-+    //        0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
-+    //        0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
-+    //        0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
-+    //        0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
-+    //        0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
-+    //        0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
-+    //        0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
-+    //        0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
-+    //        0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
-+    //     };
-+    //
-+    //     private byte[]  iv;
-+    //     private int     parameterVersion = 58;
-+    //
-+    //     protected byte[] engineGetEncoded() 
-+    //     {
-+    //         return Arrays.clone(iv);
-+    //     }
-+    //
-+    //     protected byte[] engineGetEncoded(
-+    //         String format) 
-+    //         throws IOException
-+    //     {
-+    //         if (isASN1FormatString(format))
-+    //         {
-+    //             if (parameterVersion == -1)
-+    //             {
-+    //                 return new RC2CBCParameter(engineGetEncoded()).getEncoded();
-+    //             }
-+    //             else
-+    //             {
-+    //                 return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
-+    //             }
-+    //         }
-+    //
-+    //         if (format.equals("RAW"))
-+    //         {
-+    //             return engineGetEncoded();
-+    //         }
-+    //
-+    //         return null;
-+    //     }
-+    //
-+    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-+    //         Class paramSpec) 
-+    //         throws InvalidParameterSpecException
-+    //     {
-+    //         if (paramSpec == RC2ParameterSpec.class)
-+    //         {
-+    //             if (parameterVersion != -1)
-+    //             {
-+    //                 if (parameterVersion < 256)
-+    //                 {
-+    //                     return new RC2ParameterSpec(ekb[parameterVersion], iv);
-+    //                 }
-+    //                 else
-+    //                 {
-+    //                     return new RC2ParameterSpec(parameterVersion, iv);
-+    //                 }
-+    //             }
-+    //         }
-+    //
-+    //         if (paramSpec == IvParameterSpec.class)
-+    //         {
-+    //             return new IvParameterSpec(iv);
-+    //         }
-+    //
-+    //         throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec paramSpec) 
-+    //         throws InvalidParameterSpecException
-+    //     {
-+    //         if (paramSpec instanceof IvParameterSpec)
-+    //         {
-+    //             this.iv = ((IvParameterSpec)paramSpec).getIV();
-+    //         }
-+    //         else if (paramSpec instanceof RC2ParameterSpec)
-+    //         {
-+    //             int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
-+    //             if (effKeyBits != -1)
-+    //             {
-+    //                 if (effKeyBits < 256)
-+    //                 {
-+    //                     parameterVersion = table[effKeyBits];
-+    //                 }
-+    //                 else
-+    //                 {
-+    //                     parameterVersion = effKeyBits;
-+    //                 }
-+    //             }
-+    //
-+    //             this.iv = ((RC2ParameterSpec)paramSpec).getIV();
-+    //         }
-+    //         else
-+    //         {
-+    //             throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
-+    //         }
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         byte[] params) 
-+    //         throws IOException
-+    //     {
-+    //         this.iv = Arrays.clone(params);
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         byte[] params,
-+    //         String format) 
-+    //         throws IOException
-+    //     {
-+    //         if (isASN1FormatString(format))
-+    //         {
-+    //             RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Object.fromByteArray(params));
-+    //
-+    //             if (p.getRC2ParameterVersion() != null)
-+    //             {
-+    //                 parameterVersion = p.getRC2ParameterVersion().intValue();
-+    //             }
-+    //
-+    //             iv = p.getIV();
-+    //
-+    //             return;
-+    //         }
-+    //
-+    //         if (format.equals("RAW"))
-+    //         {
-+    //             engineInit(params);
-+    //             return;
-+    //         }
-+    //
-+    //         throw new IOException("Unknown parameters format in IV parameters object");
-+    //     }
-+    //
-+    //     protected String engineToString() 
-+    //     {
-+    //         return "RC2 Parameters";
-+    //     }
-+    // }
-+    // END android-removed
-+    
-     public static class PBKDF2
-         extends JDKAlgorithmParameters
-     {
-@@ -429,7 +439,7 @@
-         extends JDKAlgorithmParameters
-     {
-         PKCS12PBEParams params;
--
-+    
-         protected byte[] engineGetEncoded() 
-         {
-             try
-@@ -441,7 +451,7 @@
-                 throw new RuntimeException("Oooops! " + e.toString());
-             }
-         }
--
-+    
-         protected byte[] engineGetEncoded(
-             String format) 
-         {
-@@ -449,10 +459,10 @@
-             {
-                 return engineGetEncoded();
-             }
--
-+    
-             return null;
-         }
--
-+    
-         protected AlgorithmParameterSpec localEngineGetParameterSpec(
-             Class paramSpec) 
-             throws InvalidParameterSpecException
-@@ -462,10 +472,10 @@
-                 return new PBEParameterSpec(params.getIV(),
-                                 params.getIterations().intValue());
-             }
--
-+    
-             throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
-         }
--
-+    
-         protected void engineInit(
-             AlgorithmParameterSpec paramSpec) 
-             throws InvalidParameterSpecException
-@@ -474,20 +484,20 @@
-             {
-                 throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
-             }
--
-+    
-             PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
--
-+    
-             this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
-                                 pbeSpec.getIterationCount());
-         }
--
-+    
-         protected void engineInit(
-             byte[] params) 
-             throws IOException
-         {
-             this.params = PKCS12PBEParams.getInstance(ASN1Object.fromByteArray(params));
-         }
--
-+    
-         protected void engineInit(
-             byte[] params,
-             String format) 
-@@ -498,10 +508,10 @@
-                 engineInit(params);
-                 return;
-             }
--
-+    
-             throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
-         }
--
-+    
-         protected String engineToString() 
-         {
-             return "PKCS12 PBE Parameters";
-@@ -725,334 +735,336 @@
-         }
-     }
-     
--    public static class GOST3410
--        extends JDKAlgorithmParameters
--    {
--        GOST3410ParameterSpec     currentSpec;
--        
--        /**
--         * Return the X.509 ASN.1 structure GOST3410Parameter.
--         * <p>
--         * <pre>
--         *  GOST3410Parameter ::= SEQUENCE {
--         *                   prime INTEGER, -- p
--         *                   subprime INTEGER, -- q
--         *                   base INTEGER, -- a}
--         * </pre>
--         */
--        protected byte[] engineGetEncoded()
--        {
--            GOST3410PublicKeyAlgParameters gost3410P = new GOST3410PublicKeyAlgParameters(new DERObjectIdentifier(currentSpec.getPublicKeyParamSetOID()), new DERObjectIdentifier(currentSpec.getDigestParamSetOID()), new DERObjectIdentifier(currentSpec.getEncryptionParamSetOID()));
--
--            try
--            {
--                return gost3410P.getEncoded(ASN1Encodable.DER);
--            }
--            catch (IOException e)
--            {
--                throw new RuntimeException("Error encoding GOST3410Parameters");
--            }
--        }
--        
--        protected byte[] engineGetEncoded(
--                String format)
--        {
--            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
--            {
--                return engineGetEncoded();
--            }
--            
--            return null;
--        }
--        
--        protected AlgorithmParameterSpec localEngineGetParameterSpec(
--                Class paramSpec)
--        throws InvalidParameterSpecException
--        {
--            if (paramSpec == GOST3410PublicKeyParameterSetSpec.class)
--            {
--                return currentSpec;
--            }
--            
--            throw new InvalidParameterSpecException("unknown parameter spec passed to GOST3410 parameters object.");
--        }
--        
--        protected void engineInit(
--                AlgorithmParameterSpec paramSpec)
--        throws InvalidParameterSpecException
--        {
--            if (!(paramSpec instanceof GOST3410ParameterSpec))
--            {
--                throw new InvalidParameterSpecException("GOST3410ParameterSpec required to initialise a GOST3410 algorithm parameters object");
--            }
--            
--            this.currentSpec = (GOST3410ParameterSpec)paramSpec;
--        }
--        
--        protected void engineInit(
--                byte[] params)
--        throws IOException
--        {
--            try
--            {
--                ASN1Sequence seq = (ASN1Sequence) ASN1Object.fromByteArray(params);
--
--                this.currentSpec = GOST3410ParameterSpec.fromPublicKeyAlg(
--                    new GOST3410PublicKeyAlgParameters(seq));
--            }
--            catch (ClassCastException e)
--            {
--                throw new IOException("Not a valid GOST3410 Parameter encoding.");
--            }
--            catch (ArrayIndexOutOfBoundsException e)
--            {
--                throw new IOException("Not a valid GOST3410 Parameter encoding.");
--            }
--        }
--        
--        protected void engineInit(
--                byte[] params,
--                String format)
--        throws IOException
--        {
--            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
--            {
--                engineInit(params);
--            }
--            else
--            {
--                throw new IOException("Unknown parameter format " + format);
--            }
--        }
--        
--        protected String engineToString()
--        {
--            return "GOST3410 Parameters";
--        }
--    }
--
--    public static class ElGamal
--        extends JDKAlgorithmParameters
--    {
--        ElGamalParameterSpec     currentSpec;
--
--        /**
--         * Return the X.509 ASN.1 structure ElGamalParameter.
--         * <p>
--         * <pre>
--         *  ElGamalParameter ::= SEQUENCE {
--         *                   prime INTEGER, -- p
--         *                   base INTEGER, -- g}
--         * </pre>
--         */
--        protected byte[] engineGetEncoded() 
--        {
--            ElGamalParameter elP = new ElGamalParameter(currentSpec.getP(), currentSpec.getG());
--
--            try
--            {
--                return elP.getEncoded(ASN1Encodable.DER);
--            }
--            catch (IOException e)
--            {
--                throw new RuntimeException("Error encoding ElGamalParameters");
--            }
--        }
--
--        protected byte[] engineGetEncoded(
--            String format) 
--        {
--            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
--            {
--                return engineGetEncoded();
--            }
--
--            return null;
--        }
--
--        protected AlgorithmParameterSpec localEngineGetParameterSpec(
--            Class paramSpec) 
--            throws InvalidParameterSpecException
--        {
--            if (paramSpec == ElGamalParameterSpec.class)
--            {
--                return currentSpec;
--            }
--            else if (paramSpec == DHParameterSpec.class)
--            {
--                return new DHParameterSpec(currentSpec.getP(), currentSpec.getG());
--            }
--
--            throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
--        }
--
--        protected void engineInit(
--            AlgorithmParameterSpec paramSpec) 
--            throws InvalidParameterSpecException
--        {
--            if (!(paramSpec instanceof ElGamalParameterSpec) && !(paramSpec instanceof DHParameterSpec))
--            {
--                throw new InvalidParameterSpecException("DHParameterSpec required to initialise a ElGamal algorithm parameters object");
--            }
--
--            if (paramSpec instanceof ElGamalParameterSpec)
--            {
--                this.currentSpec = (ElGamalParameterSpec)paramSpec;
--            }
--            else
--            {
--                DHParameterSpec s = (DHParameterSpec)paramSpec;
--                
--                this.currentSpec = new ElGamalParameterSpec(s.getP(), s.getG());
--            }
--        }
--
--        protected void engineInit(
--            byte[] params) 
--            throws IOException
--        {
--            try
--            {
--                ElGamalParameter elP = new ElGamalParameter((ASN1Sequence)ASN1Object.fromByteArray(params));
--
--                currentSpec = new ElGamalParameterSpec(elP.getP(), elP.getG());
--            }
--            catch (ClassCastException e)
--            {
--                throw new IOException("Not a valid ElGamal Parameter encoding.");
--            }
--            catch (ArrayIndexOutOfBoundsException e)
--            {
--                throw new IOException("Not a valid ElGamal Parameter encoding.");
--            }
--        }
--
--        protected void engineInit(
--            byte[] params,
--            String format) 
--            throws IOException
--        {
--            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
--            {
--                engineInit(params);
--            }
--            else
--            {
--                throw new IOException("Unknown parameter format " + format);
--            }
--        }
--
--        protected String engineToString() 
--        {
--            return "ElGamal Parameters";
--        }
--    }
--
+ 
 -    public static class IES
 -        extends JDKAlgorithmParameters
 -    {
@@ -6349,7 +8705,7 @@
 -                v.add(new DEROctetString(currentSpec.getEncodingV()));
 -                v.add(new DERInteger(currentSpec.getMacKeySize()));
 -
--                return new DERSequence(v).getEncoded(ASN1Encodable.DER);
+-                return new DERSequence(v).getEncoded(ASN1Encoding.DER);
 -            }
 -            catch (IOException e)
 -            {
@@ -6398,7 +8754,7 @@
 -        {
 -            try
 -            {
--                ASN1Sequence s = (ASN1Sequence)ASN1Object.fromByteArray(params);
+-                ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
 -
 -                this.currentSpec = new IESParameterSpec(
 -                                        ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
@@ -6436,229 +8792,6 @@
 -        }
 -    }
 +    // BEGIN android-removed
-+    // public static class GOST3410
-+    //     extends JDKAlgorithmParameters
-+    // {
-+    //     GOST3410ParameterSpec     currentSpec;
-+    //
-+    //     /**
-+    //      * Return the X.509 ASN.1 structure GOST3410Parameter.
-+    //      * <p>
-+    //      * <pre>
-+    //      *  GOST3410Parameter ::= SEQUENCE {
-+    //      *                   prime INTEGER, -- p
-+    //      *                   subprime INTEGER, -- q
-+    //      *                   base INTEGER, -- a}
-+    //      * </pre>
-+    //      */
-+    //     protected byte[] engineGetEncoded()
-+    //     {
-+    //         GOST3410PublicKeyAlgParameters gost3410P = new GOST3410PublicKeyAlgParameters(new DERObjectIdentifier(currentSpec.getPublicKeyParamSetOID()), new DERObjectIdentifier(currentSpec.getDigestParamSetOID()), new DERObjectIdentifier(currentSpec.getEncryptionParamSetOID()));
-+    //
-+    //         try
-+    //         {
-+    //             return gost3410P.getEncoded(ASN1Encodable.DER);
-+    //         }
-+    //         catch (IOException e)
-+    //         {
-+    //             throw new RuntimeException("Error encoding GOST3410Parameters");
-+    //         }
-+    //     }
-+    //
-+    //     protected byte[] engineGetEncoded(
-+    //             String format)
-+    //     {
-+    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-+    //         {
-+    //             return engineGetEncoded();
-+    //         }
-+    //
-+    //         return null;
-+    //     }
-+    //
-+    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-+    //             Class paramSpec)
-+    //     throws InvalidParameterSpecException
-+    //     {
-+    //         if (paramSpec == GOST3410PublicKeyParameterSetSpec.class)
-+    //         {
-+    //             return currentSpec;
-+    //         }
-+    //
-+    //         throw new InvalidParameterSpecException("unknown parameter spec passed to GOST3410 parameters object.");
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //             AlgorithmParameterSpec paramSpec)
-+    //     throws InvalidParameterSpecException
-+    //     {
-+    //         if (!(paramSpec instanceof GOST3410ParameterSpec))
-+    //         {
-+    //             throw new InvalidParameterSpecException("GOST3410ParameterSpec required to initialise a GOST3410 algorithm parameters object");
-+    //         }
-+    //
-+    //         this.currentSpec = (GOST3410ParameterSpec)paramSpec;
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //             byte[] params)
-+    //     throws IOException
-+    //     {
-+    //         try
-+    //         {
-+    //             ASN1Sequence seq = (ASN1Sequence) ASN1Object.fromByteArray(params);
-+    //
-+    //             this.currentSpec = GOST3410ParameterSpec.fromPublicKeyAlg(
-+    //                 new GOST3410PublicKeyAlgParameters(seq));
-+    //         }
-+    //         catch (ClassCastException e)
-+    //         {
-+    //             throw new IOException("Not a valid GOST3410 Parameter encoding.");
-+    //         }
-+    //         catch (ArrayIndexOutOfBoundsException e)
-+    //         {
-+    //             throw new IOException("Not a valid GOST3410 Parameter encoding.");
-+    //         }
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //             byte[] params,
-+    //             String format)
-+    //     throws IOException
-+    //     {
-+    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-+    //         {
-+    //             engineInit(params);
-+    //         }
-+    //         else
-+    //         {
-+    //             throw new IOException("Unknown parameter format " + format);
-+    //         }
-+    //     }
-+    //
-+    //     protected String engineToString()
-+    //     {
-+    //         return "GOST3410 Parameters";
-+    //     }
-+    // }
-+
-+    // public static class ElGamal
-+    //     extends JDKAlgorithmParameters
-+    // {
-+    //     ElGamalParameterSpec     currentSpec;
-+    //
-+    //     /**
-+    //      * Return the X.509 ASN.1 structure ElGamalParameter.
-+    //      * <p>
-+    //      * <pre>
-+    //      *  ElGamalParameter ::= SEQUENCE {
-+    //      *                   prime INTEGER, -- p
-+    //      *                   base INTEGER, -- g}
-+    //      * </pre>
-+    //      */
-+    //     protected byte[] engineGetEncoded() 
-+    //     {
-+    //         ElGamalParameter elP = new ElGamalParameter(currentSpec.getP(), currentSpec.getG());
-+    //
-+    //         try
-+    //         {
-+    //             return elP.getEncoded(ASN1Encodable.DER);
-+    //         }
-+    //         catch (IOException e)
-+    //         {
-+    //             throw new RuntimeException("Error encoding ElGamalParameters");
-+    //         }
-+    //     }
-+    //
-+    //     protected byte[] engineGetEncoded(
-+    //         String format) 
-+    //     {
-+    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-+    //         {
-+    //             return engineGetEncoded();
-+    //         }
-+    //
-+    //         return null;
-+    //     }
-+    //
-+    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-+    //         Class paramSpec) 
-+    //         throws InvalidParameterSpecException
-+    //     {
-+    //         if (paramSpec == ElGamalParameterSpec.class)
-+    //         {
-+    //             return currentSpec;
-+    //         }
-+    //         else if (paramSpec == DHParameterSpec.class)
-+    //         {
-+    //             return new DHParameterSpec(currentSpec.getP(), currentSpec.getG());
-+    //         }
-+    //
-+    //         throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec paramSpec) 
-+    //         throws InvalidParameterSpecException
-+    //     {
-+    //         if (!(paramSpec instanceof ElGamalParameterSpec) && !(paramSpec instanceof DHParameterSpec))
-+    //         {
-+    //             throw new InvalidParameterSpecException("DHParameterSpec required to initialise a ElGamal algorithm parameters object");
-+    //         }
-+    //
-+    //         if (paramSpec instanceof ElGamalParameterSpec)
-+    //         {
-+    //             this.currentSpec = (ElGamalParameterSpec)paramSpec;
-+    //         }
-+    //         else
-+    //         {
-+    //             DHParameterSpec s = (DHParameterSpec)paramSpec;
-+    //
-+    //             this.currentSpec = new ElGamalParameterSpec(s.getP(), s.getG());
-+    //         }
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         byte[] params) 
-+    //         throws IOException
-+    //     {
-+    //         try
-+    //         {
-+    //             ElGamalParameter elP = new ElGamalParameter((ASN1Sequence)ASN1Object.fromByteArray(params));
-+    //
-+    //             currentSpec = new ElGamalParameterSpec(elP.getP(), elP.getG());
-+    //         }
-+    //         catch (ClassCastException e)
-+    //         {
-+    //             throw new IOException("Not a valid ElGamal Parameter encoding.");
-+    //         }
-+    //         catch (ArrayIndexOutOfBoundsException e)
-+    //         {
-+    //             throw new IOException("Not a valid ElGamal Parameter encoding.");
-+    //         }
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         byte[] params,
-+    //         String format) 
-+    //         throws IOException
-+    //     {
-+    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-+    //         {
-+    //             engineInit(params);
-+    //         }
-+    //         else
-+    //         {
-+    //             throw new IOException("Unknown parameter format " + format);
-+    //         }
-+    //     }
-+    //
-+    //     protected String engineToString() 
-+    //     {
-+    //         return "ElGamal Parameters";
-+    //     }
-+    // }
-+    //
 +    // public static class IES
 +    //     extends JDKAlgorithmParameters
 +    // {
@@ -6678,7 +8811,7 @@
 +    //             v.add(new DEROctetString(currentSpec.getEncodingV()));
 +    //             v.add(new DERInteger(currentSpec.getMacKeySize()));
 +    //
-+    //             return new DERSequence(v).getEncoded(ASN1Encodable.DER);
++    //             return new DERSequence(v).getEncoded(ASN1Encoding.DER);
 +    //         }
 +    //         catch (IOException e)
 +    //         {
@@ -6727,7 +8860,7 @@
 +    //     {
 +    //         try
 +    //         {
-+    //             ASN1Sequence s = (ASN1Sequence)ASN1Object.fromByteArray(params);
++    //             ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
 +    //
 +    //             this.currentSpec = new IESParameterSpec(
 +    //                                     ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
@@ -6765,1310 +8898,10 @@
 +    //     }
 +    // }
 +    // END android-removed
-     
-     public static class OAEP
-         extends JDKAlgorithmParameters
-@@ -1066,11 +1078,15 @@
-         {
-             AlgorithmIdentifier     hashAlgorithm = new AlgorithmIdentifier(
-                                                             JCEDigestUtil.getOID(currentSpec.getDigestAlgorithm()),
--                                                            new DERNull());
-+                                                            // BEGIN android-changed
-+                                                            DERNull.INSTANCE);
-+                                                            // END android-changed
-             MGF1ParameterSpec       mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
-             AlgorithmIdentifier     maskGenAlgorithm = new AlgorithmIdentifier(
-                                                             PKCSObjectIdentifiers.id_mgf1, 
--                                                            new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), new DERNull()));
-+                                                            // BEGIN android-changed
-+                                                            new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
-+                                                            // END android-changed
-             PSource.PSpecified      pSource = (PSource.PSpecified)currentSpec.getPSource();
-             AlgorithmIdentifier     pSourceAlgorithm = new AlgorithmIdentifier(
-                                                             PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
-@@ -1167,110 +1183,116 @@
-         }
-     }
-     
--    public static class PSS
--        extends JDKAlgorithmParameters
--    {  
--        PSSParameterSpec     currentSpec;
--    
--        /**
--         * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
--         */
--        protected byte[] engineGetEncoded() 
--            throws IOException
--        {
--            PSSParameterSpec    pssSpec = currentSpec;
--            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
--                                                JCEDigestUtil.getOID(pssSpec.getDigestAlgorithm()),
--                                                new DERNull());
--            MGF1ParameterSpec   mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
--            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
--                                                PKCSObjectIdentifiers.id_mgf1, 
--                                                new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), new DERNull()));
--            RSASSAPSSparams     pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new DERInteger(pssSpec.getSaltLength()), new DERInteger(pssSpec.getTrailerField()));
--            
--            return pssP.getEncoded("DER");
--        }
--    
--        protected byte[] engineGetEncoded(
--            String format) 
--            throws IOException
--        {
--            if (format.equalsIgnoreCase("X.509")
--                    || format.equalsIgnoreCase("ASN.1"))
--            {
--                return engineGetEncoded();
--            }
--    
--            return null;
--        }
--    
--        protected AlgorithmParameterSpec localEngineGetParameterSpec(
--            Class paramSpec) 
--            throws InvalidParameterSpecException
--        {
--            if (paramSpec == PSSParameterSpec.class && currentSpec != null)
--            {
--                return currentSpec;
--            }
--    
--            throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
--        }
--    
--        protected void engineInit(
--            AlgorithmParameterSpec paramSpec) 
--            throws InvalidParameterSpecException
--        {
--            if (!(paramSpec instanceof PSSParameterSpec))
--            {
--                throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
--            }
--    
--            this.currentSpec = (PSSParameterSpec)paramSpec;
--        }
--    
--        protected void engineInit(
--            byte[] params) 
--            throws IOException
--        {
--            try
--            {
--                RSASSAPSSparams pssP = new RSASSAPSSparams((ASN1Sequence)ASN1Object.fromByteArray(params));
--
--                currentSpec = new PSSParameterSpec(
--                                       pssP.getHashAlgorithm().getObjectId().getId(), 
--                                       pssP.getMaskGenAlgorithm().getObjectId().getId(), 
--                                       new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getObjectId().getId()),
--                                       pssP.getSaltLength().getValue().intValue(),
--                                       pssP.getTrailerField().getValue().intValue());
--            }
--            catch (ClassCastException e)
--            {
--                throw new IOException("Not a valid PSS Parameter encoding.");
--            }
--            catch (ArrayIndexOutOfBoundsException e)
--            {
--                throw new IOException("Not a valid PSS Parameter encoding.");
--            }
--        }
--    
--        protected void engineInit(
--            byte[] params,
--            String format) 
--            throws IOException
--        {
--            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
--            {
--                engineInit(params);
--            }
--            else
--            {
--                throw new IOException("Unknown parameter format " + format);
--            }
--        }
--    
--        protected String engineToString() 
--        {
--            return "PSS Parameters";
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class PSS
-+    //     extends JDKAlgorithmParameters
-+    // {  
-+    //     PSSParameterSpec     currentSpec;
-+    //
-+    //     /**
-+    //      * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
-+    //      */
-+    //     protected byte[] engineGetEncoded() 
-+    //         throws IOException
-+    //     {
-+    //         PSSParameterSpec    pssSpec = currentSpec;
-+    //         AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
-+    //                                             JCEDigestUtil.getOID(pssSpec.getDigestAlgorithm()),
-+    //                                             // BEGIN android-changed
-+    //                                             DERNull.INSTANCE);
-+    //                                             // END android-changed
-+    //         MGF1ParameterSpec   mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
-+    //         AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
-+    //                                             PKCSObjectIdentifiers.id_mgf1, 
-+    //                                             // BEGIN android-changed
-+    //                                             new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
-+    //                                             // END android-changed
-+    //         RSASSAPSSparams     pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new DERInteger(pssSpec.getSaltLength()), new DERInteger(pssSpec.getTrailerField()));
-+    //
-+    //         return pssP.getEncoded("DER");
-+    //     }
-+    //
-+    //     protected byte[] engineGetEncoded(
-+    //         String format) 
-+    //         throws IOException
-+    //     {
-+    //         if (format.equalsIgnoreCase("X.509")
-+    //                 || format.equalsIgnoreCase("ASN.1"))
-+    //         {
-+    //             return engineGetEncoded();
-+    //         }
-+    //
-+    //         return null;
-+    //     }
-+    //
-+    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-+    //         Class paramSpec) 
-+    //         throws InvalidParameterSpecException
-+    //     {
-+    //         if (paramSpec == PSSParameterSpec.class && currentSpec != null)
-+    //         {
-+    //             return currentSpec;
-+    //         }
-+    //
-+    //         throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec paramSpec) 
-+    //         throws InvalidParameterSpecException
-+    //     {
-+    //         if (!(paramSpec instanceof PSSParameterSpec))
-+    //         {
-+    //             throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
-+    //         }
-+    //
-+    //         this.currentSpec = (PSSParameterSpec)paramSpec;
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         byte[] params) 
-+    //         throws IOException
-+    //     {
-+    //         try
-+    //         {
-+    //             RSASSAPSSparams pssP = new RSASSAPSSparams((ASN1Sequence)ASN1Object.fromByteArray(params));
-+    //
-+    //             currentSpec = new PSSParameterSpec(
-+    //                                    pssP.getHashAlgorithm().getObjectId().getId(), 
-+    //                                    pssP.getMaskGenAlgorithm().getObjectId().getId(), 
-+    //                                    new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getObjectId().getId()),
-+    //                                    pssP.getSaltLength().getValue().intValue(),
-+    //                                    pssP.getTrailerField().getValue().intValue());
-+    //         }
-+    //         catch (ClassCastException e)
-+    //         {
-+    //             throw new IOException("Not a valid PSS Parameter encoding.");
-+    //         }
-+    //         catch (ArrayIndexOutOfBoundsException e)
-+    //         {
-+    //             throw new IOException("Not a valid PSS Parameter encoding.");
-+    //         }
-+    //     }
-+    //
-+    //     protected void engineInit(
-+    //         byte[] params,
-+    //         String format) 
-+    //         throws IOException
-+    //     {
-+    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-+    //         {
-+    //             engineInit(params);
-+    //         }
-+    //         else
-+    //         {
-+    //             throw new IOException("Unknown parameter format " + format);
-+    //         }
-+    //     }
-+    //
-+    //     protected String engineToString() 
-+    //     {
-+    //         return "PSS Parameters";
-+    //     }
-+    // }
-+    // END android-removed
  }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDSASigner.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDSASigner.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDSASigner.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDSASigner.java	2012-07-27 18:48:00.031478939 +0000
-@@ -23,13 +23,17 @@
- import org.bouncycastle.crypto.Digest;
- import org.bouncycastle.crypto.digests.NullDigest;
- import org.bouncycastle.crypto.digests.SHA1Digest;
--import org.bouncycastle.crypto.digests.SHA224Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.SHA224Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.SHA256Digest;
- import org.bouncycastle.crypto.digests.SHA384Digest;
- import org.bouncycastle.crypto.digests.SHA512Digest;
- import org.bouncycastle.crypto.params.ParametersWithRandom;
- import org.bouncycastle.crypto.signers.DSASigner;
--import org.bouncycastle.jce.interfaces.GOST3410Key;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.interfaces.GOST3410Key;
-+// END android-removed
- 
- public class JDKDSASigner
-     extends SignatureSpi
-@@ -53,11 +57,16 @@
-     {
-         CipherParameters    param;
- 
--        if (publicKey instanceof GOST3410Key)
--        {
--            param = GOST3410Util.generatePublicKeyParameter(publicKey);
--        }
--        else if (publicKey instanceof DSAKey)
-+        // BEGIN android-removed
-+        // if (publicKey instanceof GOST3410Key)
-+        // {
-+        //     param = GOST3410Util.generatePublicKeyParameter(publicKey);
-+        // }
-+        // else if (publicKey instanceof DSAKey)
-+        // END android-removed
-+        // BEGIN android-added
-+        if (publicKey instanceof DSAKey)
-+        // END android-added
-         {
-             param = DSAUtil.generatePublicKeyParameter(publicKey);
-         }
-@@ -103,14 +112,18 @@
-     {
-         CipherParameters    param;
- 
--        if (privateKey instanceof GOST3410Key)
--        {
--            param = GOST3410Util.generatePrivateKeyParameter(privateKey);
--        }
--        else
--        {
-+        // BEGIN android-removed
-+        // if (privateKey instanceof GOST3410Key)
-+        // {
-+        //     param = GOST3410Util.generatePrivateKeyParameter(privateKey);
-+        // }
-+        // else
-+        // {
-+        // END android-removed
-             param = DSAUtil.generatePrivateKeyParameter(privateKey);
--        }
-+        // BEGIN android-removed
-+        // }
-+        // END android-removed
- 
-         if (random != null)
-         {
-@@ -231,42 +244,44 @@
-             super(new SHA1Digest(), new DSASigner());
-         }
-     }
--
--    static public class dsa224
--        extends JDKDSASigner
--    {
--        public dsa224()
--        {
--            super(new SHA224Digest(), new DSASigner());
--        }
--    }
--    
--    static public class dsa256
--        extends JDKDSASigner
--    {
--        public dsa256()
--        {
--            super(new SHA256Digest(), new DSASigner());
--        }
--    }
-     
--    static public class dsa384
--        extends JDKDSASigner
--    {
--        public dsa384()
--        {
--            super(new SHA384Digest(), new DSASigner());
--        }
--    }
--    
--    static public class dsa512
--        extends JDKDSASigner
--    {
--        public dsa512()
--        {
--            super(new SHA512Digest(), new DSASigner());
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class dsa224
-+    //     extends JDKDSASigner
-+    // {
-+    //     public dsa224()
-+    //     {
-+    //         super(new SHA224Digest(), new DSASigner());
-+    //     }
-+    // }
-+    //
-+    // static public class dsa256
-+    //     extends JDKDSASigner
-+    // {
-+    //     public dsa256()
-+    //     {
-+    //         super(new SHA256Digest(), new DSASigner());
-+    //     }
-+    // }
-+    //
-+    // static public class dsa384
-+    //     extends JDKDSASigner
-+    // {
-+    //     public dsa384()
-+    //     {
-+    //         super(new SHA384Digest(), new DSASigner());
-+    //     }
-+    // }
-+    //
-+    // static public class dsa512
-+    //     extends JDKDSASigner
-+    // {
-+    //     public dsa512()
-+    //     {
-+    //         super(new SHA512Digest(), new DSASigner());
-+    //     }
-+    // }
-+    // END android-removed
- 
-     static public class noneDSA
-         extends JDKDSASigner
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDigestSignature.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDigestSignature.java	2012-07-27 18:48:00.031478939 +0000
-@@ -23,15 +23,21 @@
- import org.bouncycastle.crypto.AsymmetricBlockCipher;
- import org.bouncycastle.crypto.CipherParameters;
- import org.bouncycastle.crypto.Digest;
--import org.bouncycastle.crypto.digests.MD2Digest;
--import org.bouncycastle.crypto.digests.MD4Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.MD2Digest;
-+// import org.bouncycastle.crypto.digests.MD4Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.MD5Digest;
- import org.bouncycastle.crypto.digests.NullDigest;
--import org.bouncycastle.crypto.digests.RIPEMD128Digest;
--import org.bouncycastle.crypto.digests.RIPEMD160Digest;
--import org.bouncycastle.crypto.digests.RIPEMD256Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
-+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// 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.SHA256Digest;
- import org.bouncycastle.crypto.digests.SHA384Digest;
- import org.bouncycastle.crypto.digests.SHA512Digest;
-@@ -265,14 +271,16 @@
-         }
-     }
- 
--    static public class SHA224WithRSAEncryption
--        extends JDKDigestSignature
--    {
--        public SHA224WithRSAEncryption()
--        {
--            super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class SHA224WithRSAEncryption
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public SHA224WithRSAEncryption()
-+    //     {
-+    //         super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- 
-     static public class SHA256WithRSAEncryption
-         extends JDKDigestSignature
-@@ -301,23 +309,25 @@
-         }
-     }
- 
--    static public class MD2WithRSAEncryption
--        extends JDKDigestSignature
--    {
--        public MD2WithRSAEncryption()
--        {
--            super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class MD4WithRSAEncryption
--        extends JDKDigestSignature
--    {
--        public MD4WithRSAEncryption()
--        {
--            super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class MD2WithRSAEncryption
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public MD2WithRSAEncryption()
-+    //     {
-+    //         super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class MD4WithRSAEncryption
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public MD4WithRSAEncryption()
-+    //     {
-+    //         super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- 
-     static public class MD5WithRSAEncryption
-         extends JDKDigestSignature
-@@ -328,39 +338,41 @@
-         }
-     }
- 
--    static public class RIPEMD160WithRSAEncryption
--        extends JDKDigestSignature
--    {
--        public RIPEMD160WithRSAEncryption()
--        {
--            super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class RIPEMD128WithRSAEncryption
--        extends JDKDigestSignature
--    {
--        public RIPEMD128WithRSAEncryption()
--        {
--            super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class RIPEMD256WithRSAEncryption
--        extends JDKDigestSignature
--    {
--        public RIPEMD256WithRSAEncryption()
--        {
--            super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class noneRSA
--        extends JDKDigestSignature
--    {
--        public noneRSA()
--        {
--            super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class RIPEMD160WithRSAEncryption
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public RIPEMD160WithRSAEncryption()
-+    //     {
-+    //         super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class RIPEMD128WithRSAEncryption
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public RIPEMD128WithRSAEncryption()
-+    //     {
-+    //         super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class RIPEMD256WithRSAEncryption
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public RIPEMD256WithRSAEncryption()
-+    //     {
-+    //         super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    //
-+    // static public class noneRSA
-+    //     extends JDKDigestSignature
-+    // {
-+    //     public noneRSA()
-+    //     {
-+    //         super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyFactory.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyFactory.java	2012-07-27 18:48:00.031478939 +0000
-@@ -36,17 +36,21 @@
- import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
- import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
- import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
--import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
--import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
--import org.bouncycastle.jce.spec.ElGamalPrivateKeySpec;
--import org.bouncycastle.jce.spec.ElGamalPublicKeySpec;
--import org.bouncycastle.jce.spec.GOST3410PrivateKeySpec;
--import org.bouncycastle.jce.spec.GOST3410PublicKeySpec;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
-+// import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
-+// import org.bouncycastle.jce.spec.ElGamalPrivateKeySpec;
-+// import org.bouncycastle.jce.spec.ElGamalPublicKeySpec;
-+// import org.bouncycastle.jce.spec.GOST3410PrivateKeySpec;
-+// import org.bouncycastle.jce.spec.GOST3410PublicKeySpec;
-+// END android-removed
- 
- public abstract class JDKKeyFactory
-     extends KeyFactorySpi
- {
--    protected boolean elGamalFactory = false;
-+    // BEGIN android-removed
-+    // protected boolean elGamalFactory = false;
-+    // END android-removed
-     
-     public JDKKeyFactory()
-     {
-@@ -140,6 +144,20 @@
-            
-            return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
-        }
-+       // BEGIN android-added
-+       else if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
-+       {
-+            DSAPublicKey    k = (DSAPublicKey)key;
-+
-+            return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
-+       }
-+       else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof DSAPrivateKey)
-+       {
-+            DSAPrivateKey    k = (DSAPrivateKey)key;
-+
-+            return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
-+       }
-+       // END android-added
- 
-        throw new RuntimeException("not implemented yet " + key + " " + spec);
-     }
-@@ -162,25 +180,33 @@
-         }
-         else if (key instanceof DHPublicKey)
-         {
--            if (elGamalFactory)
--            {
--                return new JCEElGamalPublicKey((DHPublicKey)key);
--            }
--            else
--            {
-+            // BEGIN android-removed
-+            // if (elGamalFactory)
-+            // {
-+            //     return new JCEElGamalPublicKey((DHPublicKey)key);
-+            // }
-+            // else
-+            // {
-+            // END android-removed
-                 return new JCEDHPublicKey((DHPublicKey)key);
--            }
-+            // BEGIN android-removed
-+            // }
-+            // END android-removed
-         }
-         else if (key instanceof DHPrivateKey)
-         {
--            if (elGamalFactory)
--            {
--                return new JCEElGamalPrivateKey((DHPrivateKey)key);
--            }
--            else
--            {
-+            // BEGIN android-removed
-+            // if (elGamalFactory)
-+            // {
-+            //     return new JCEElGamalPrivateKey((DHPrivateKey)key);
-+            // }
-+            // else
-+            // {
-+            // END android-removed
-                 return new JCEDHPrivateKey((DHPrivateKey)key);
--            }
-+            // BEGIN android-removed
-+            // }
-+            // END android-removed
-         }
-         else if (key instanceof DSAPublicKey)
-         {
-@@ -190,14 +216,16 @@
-         {
-             return new JDKDSAPrivateKey((DSAPrivateKey)key);
-         }
--        else if (key instanceof ElGamalPublicKey)
--        {
--            return new JCEElGamalPublicKey((ElGamalPublicKey)key);
--        }
--        else if (key instanceof ElGamalPrivateKey)
--        {
--            return new JCEElGamalPrivateKey((ElGamalPrivateKey)key);
--        }
-+        // BEGIN android-removed
-+        // else if (key instanceof ElGamalPublicKey)
-+        // {
-+        //     return new JCEElGamalPublicKey((ElGamalPublicKey)key);
-+        // }
-+        // else if (key instanceof ElGamalPrivateKey)
-+        // {
-+        //    return new JCEElGamalPrivateKey((ElGamalPrivateKey)key);
-+        // }
-+        // END android-removed
- 
-         throw new InvalidKeyException("key type unknown");
-     }
-@@ -233,10 +261,12 @@
-         {
-             return new JCEDHPublicKey(info);
-         }
--        else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
--        {
--            return new JCEElGamalPublicKey(info);
--        }
-+        // BEGIN android-removed
-+        // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
-+        // {
-+        //     return new JCEElGamalPublicKey(info);
-+        // }
-+        // END android-removed
-         else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
-         {
-             return new JDKDSAPublicKey(info);
-@@ -249,14 +279,15 @@
-         {
-             return new JCEECPublicKey(info);
-         }
--        else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
--        {
--            return new JDKGOST3410PublicKey(info);
--        }
--        else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
--        {
--            return new JCEECPublicKey(info);
--        }
-+        // BEGIN android-removed
-+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
-+        // {
-+        //     return new JDKGOST3410PublicKey(info);
-+        // }
-+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
-+        // {
-+        //     return new JCEECPublicKey(info);
-+        // }
-         else
-         {
-             throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-@@ -294,10 +325,12 @@
-         {
-               return new JCEDHPrivateKey(info);
-         }
--        else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
--        {
--              return new JCEElGamalPrivateKey(info);
--        }
-+        // BEGIN android-removed
-+        // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
-+        // {
-+        //       return new JCEElGamalPrivateKey(info);
-+        // }
-+        // END android-removed
-         else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
-         {
-               return new JDKDSAPrivateKey(info);
-@@ -306,14 +339,16 @@
-         {
-               return new JCEECPrivateKey(info);
-         }
--        else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
--        {
--              return new JDKGOST3410PrivateKey(info);
--        }
--        else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
--        {
--              return new JCEECPrivateKey(info);
--        }
-+        // BEGIN android-removed
-+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
-+        // {
-+        //       return new JDKGOST3410PrivateKey(info);
-+        // }
-+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
-+        // {
-+        //       return new JCEECPrivateKey(info);
-+        // }
-+        // END android-removed
-         else
-         {
-             throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-@@ -444,89 +479,92 @@
-         }
-     }
- 
--    public static class GOST3410
--        extends JDKKeyFactory
--    {
--        public GOST3410()
--        {
--        }
--        
--        protected PrivateKey engineGeneratePrivate(
--                KeySpec    keySpec)
--        throws InvalidKeySpecException
--        {
--            if (keySpec instanceof GOST3410PrivateKeySpec)
--            {
--                return new JDKGOST3410PrivateKey((GOST3410PrivateKeySpec)keySpec);
--            }
--
--            return super.engineGeneratePrivate(keySpec);
--        }
--        
--        protected PublicKey engineGeneratePublic(
--                KeySpec    keySpec)
--        throws InvalidKeySpecException
--        {
--            if (keySpec instanceof GOST3410PublicKeySpec)
--            {
--                return new JDKGOST3410PublicKey((GOST3410PublicKeySpec)keySpec);
--            }
--
--            return super.engineGeneratePublic(keySpec);
--        }
--    }
--    
--    public static class ElGamal
--        extends JDKKeyFactory
--    {
--        public ElGamal()
--        {
--            elGamalFactory = true;
--        }
--
--        protected PrivateKey engineGeneratePrivate(
--            KeySpec    keySpec)
--            throws InvalidKeySpecException
--        {
--            if (keySpec instanceof ElGamalPrivateKeySpec)
--            {
--                return new JCEElGamalPrivateKey((ElGamalPrivateKeySpec)keySpec);
--            }
--            else if (keySpec instanceof DHPrivateKeySpec)
--            {
--                return new JCEElGamalPrivateKey((DHPrivateKeySpec)keySpec);
--            }
--
--            return super.engineGeneratePrivate(keySpec);
--        }
-+    // BEGIN android-removed
-+    // public static class GOST3410
-+    //     extends JDKKeyFactory
-+    // {
-+    //     public GOST3410()
-+    //     {
-+    //     }
-+    //
-+    //     protected PrivateKey engineGeneratePrivate(
-+    //             KeySpec    keySpec)
-+    //     throws InvalidKeySpecException
-+    //     {
-+    //         if (keySpec instanceof GOST3410PrivateKeySpec)
-+    //         {
-+    //             return new JDKGOST3410PrivateKey((GOST3410PrivateKeySpec)keySpec);
-+    //         }
-+    //
-+    //         return super.engineGeneratePrivate(keySpec);
-+    //     }
-+    //
-+    //     protected PublicKey engineGeneratePublic(
-+    //             KeySpec    keySpec)
-+    //     throws InvalidKeySpecException
-+    //     {
-+    //         if (keySpec instanceof GOST3410PublicKeySpec)
-+    //         {
-+    //             return new JDKGOST3410PublicKey((GOST3410PublicKeySpec)keySpec);
-+    //         }
-+    //
-+    //         return super.engineGeneratePublic(keySpec);
-+    //     }
-+    // }
-     
--        protected PublicKey engineGeneratePublic(
--            KeySpec    keySpec)
--            throws InvalidKeySpecException
--        {
--            if (keySpec instanceof ElGamalPublicKeySpec)
--            {
--                return new JCEElGamalPublicKey((ElGamalPublicKeySpec)keySpec);
--            }
--            else if (keySpec instanceof DHPublicKeySpec)
--            {
--                return new JCEElGamalPublicKey((DHPublicKeySpec)keySpec);
--            }
--
--            return super.engineGeneratePublic(keySpec);
--        }
--    }
--
--
--    /**
--     * This isn't really correct, however the class path project API seems to think such
--     * a key factory will exist.
--     */
--    public static class X509
--        extends JDKKeyFactory
--    {
--        public X509()
--        {
--        }
--    }
-+    // public static class ElGamal
-+    //     extends JDKKeyFactory
-+    // {
-+    //     public ElGamal()
-+    //     {
-+    //         elGamalFactory = true;
-+    //     }
-+    //
-+    //     protected PrivateKey engineGeneratePrivate(
-+    //         KeySpec    keySpec)
-+    //         throws InvalidKeySpecException
-+    //     {
-+    //         if (keySpec instanceof ElGamalPrivateKeySpec)
-+    //         {
-+    //             return new JCEElGamalPrivateKey((ElGamalPrivateKeySpec)keySpec);
-+    //         }
-+    //         else if (keySpec instanceof DHPrivateKeySpec)
-+    //         {
-+    //             return new JCEElGamalPrivateKey((DHPrivateKeySpec)keySpec);
-+    //         }
-+    //
-+    //         return super.engineGeneratePrivate(keySpec);
-+    //     }
-+    //
-+    //     protected PublicKey engineGeneratePublic(
-+    //         KeySpec    keySpec)
-+    //         throws InvalidKeySpecException
-+    //     {
-+    //         if (keySpec instanceof ElGamalPublicKeySpec)
-+    //         {
-+    //             return new JCEElGamalPublicKey((ElGamalPublicKeySpec)keySpec);
-+    //         }
-+    //         else if (keySpec instanceof DHPublicKeySpec)
-+    //         {
-+    //             return new JCEElGamalPublicKey((DHPublicKeySpec)keySpec);
-+    //         }
-+    //
-+    //         return super.engineGeneratePublic(keySpec);
-+    //     }
-+    // }
-+    //
-+    //
-+    //
-+    // /**
-+    //  * This isn't really correct, however the class path project API seems to think such
-+    //  * a key factory will exist.
-+    //  */
-+    // public static class X509
-+    //     extends JDKKeyFactory
-+    // {
-+    //     public X509()
-+    //     {
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2012-07-27 18:48:00.031478939 +0000
-@@ -6,9 +6,11 @@
- import org.bouncycastle.crypto.generators.DHParametersGenerator;
- import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
- import org.bouncycastle.crypto.generators.DSAParametersGenerator;
--import org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator;
--import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
--import org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator;
-+// import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
-+// import org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator;
-+// END android-removed
- import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
- import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
- import org.bouncycastle.crypto.params.DHParameters;
-@@ -18,20 +20,24 @@
- import org.bouncycastle.crypto.params.DSAParameters;
- import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
- import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
--import org.bouncycastle.crypto.params.ElGamalKeyGenerationParameters;
--import org.bouncycastle.crypto.params.ElGamalParameters;
--import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
--import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
--import org.bouncycastle.crypto.params.GOST3410KeyGenerationParameters;
--import org.bouncycastle.crypto.params.GOST3410Parameters;
--import org.bouncycastle.crypto.params.GOST3410PrivateKeyParameters;
--import org.bouncycastle.crypto.params.GOST3410PublicKeyParameters;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.params.ElGamalKeyGenerationParameters;
-+// import org.bouncycastle.crypto.params.ElGamalParameters;
-+// import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
-+// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
-+// import org.bouncycastle.crypto.params.GOST3410KeyGenerationParameters;
-+// import org.bouncycastle.crypto.params.GOST3410Parameters;
-+// import org.bouncycastle.crypto.params.GOST3410PrivateKeyParameters;
-+// import org.bouncycastle.crypto.params.GOST3410PublicKeyParameters;
-+// END android-removed
- import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
- import org.bouncycastle.crypto.params.RSAKeyParameters;
- import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
--import org.bouncycastle.jce.spec.ElGamalParameterSpec;
--import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
--import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.spec.ElGamalParameterSpec;
-+// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-+// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-+// END android-removed
- 
- import java.math.BigInteger;
- import java.security.InvalidAlgorithmParameterException;
-@@ -163,7 +169,9 @@
-         {
-             if (!initialised)
-             {
--                Integer paramStrength = new Integer(strength);
-+                // BEGIN android-changed
-+                Integer paramStrength = Integer.valueOf(strength);
-+                // END android-changed
- 
-                 if (params.containsKey(paramStrength))
-                 {
-@@ -260,139 +268,143 @@
-         }
-     }
- 
--    public static class ElGamal
--        extends JDKKeyPairGenerator
--    {
--        ElGamalKeyGenerationParameters  param;
--        ElGamalKeyPairGenerator         engine = new ElGamalKeyPairGenerator();
--        int                             strength = 1024;
--        int                             certainty = 20;
--        SecureRandom                    random = new SecureRandom();
--        boolean                         initialised = false;
--
--        public ElGamal()
--        {
--            super("ElGamal");
--        }
--
--        public void initialize(
--            int             strength,
--            SecureRandom    random)
--        {
--            this.strength = strength;
--            this.random = random;
--        }
--
--        public void initialize(
--            AlgorithmParameterSpec  params,
--            SecureRandom            random)
--            throws InvalidAlgorithmParameterException
--        {
--            if (!(params instanceof ElGamalParameterSpec) && !(params instanceof DHParameterSpec))
--            {
--                throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec or an ElGamalParameterSpec");
--            }
--            
--            if (params instanceof ElGamalParameterSpec)
--            {
--                ElGamalParameterSpec     elParams = (ElGamalParameterSpec)params;
--
--                param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(elParams.getP(), elParams.getG()));
--            }
--            else
--            {
--                DHParameterSpec     dhParams = (DHParameterSpec)params;
--
--                param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(dhParams.getP(), dhParams.getG(), dhParams.getL()));
--            }
--
--            engine.init(param);
--            initialised = true;
--        }
--
--        public KeyPair generateKeyPair()
--        {
--            if (!initialised)
--            {
--                ElGamalParametersGenerator   pGen = new ElGamalParametersGenerator();
--
--                pGen.init(strength, certainty, random);
--                param = new ElGamalKeyGenerationParameters(random, pGen.generateParameters());
--                engine.init(param);
--                initialised = true;
--            }
--
--            AsymmetricCipherKeyPair         pair = engine.generateKeyPair();
--            ElGamalPublicKeyParameters      pub = (ElGamalPublicKeyParameters)pair.getPublic();
--            ElGamalPrivateKeyParameters     priv = (ElGamalPrivateKeyParameters)pair.getPrivate();
--
--            return new KeyPair(new JCEElGamalPublicKey(pub),
--                               new JCEElGamalPrivateKey(priv));
--        }
--    }
--
--    public static class GOST3410
--        extends JDKKeyPairGenerator
--    {
--        GOST3410KeyGenerationParameters param;
--        GOST3410KeyPairGenerator        engine = new GOST3410KeyPairGenerator();
--        GOST3410ParameterSpec           gost3410Params;
--        int                             strength = 1024;
--        SecureRandom                    random = null;
--        boolean                         initialised = false;
--
--        public GOST3410()
--        {
--            super("GOST3410");
--        }
--
--        public void initialize(
--            int             strength,
--            SecureRandom    random)
--        {
--            this.strength = strength;
--            this.random = random;
--        }
--    
--        private void init(
--            GOST3410ParameterSpec gParams,
--            SecureRandom          random)
--        {
--            GOST3410PublicKeyParameterSetSpec spec = gParams.getPublicKeyParameters();
--            
--            param = new GOST3410KeyGenerationParameters(random, new GOST3410Parameters(spec.getP(), spec.getQ(), spec.getA()));
--            
--            engine.init(param);
--            
--            initialised = true;
--            gost3410Params = gParams;
--        }
--        
--        public void initialize(
--            AlgorithmParameterSpec  params,
--            SecureRandom            random)
--            throws InvalidAlgorithmParameterException
--        {
--            if (!(params instanceof GOST3410ParameterSpec))
--            {
--                throw new InvalidAlgorithmParameterException("parameter object not a GOST3410ParameterSpec");
--            }
--            
--            init((GOST3410ParameterSpec)params, random);
--        }
--
--        public KeyPair generateKeyPair()
--        {
--            if (!initialised)
--            {
--                init(new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()), new SecureRandom());
--            }
--            
--            AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
--            GOST3410PublicKeyParameters  pub = (GOST3410PublicKeyParameters)pair.getPublic();
--            GOST3410PrivateKeyParameters priv = (GOST3410PrivateKeyParameters)pair.getPrivate();
--            
--            return new KeyPair(new JDKGOST3410PublicKey(pub, gost3410Params), new JDKGOST3410PrivateKey(priv, gost3410Params));
--        }
--   }
-+    // BEGIN android-removed
-+    // public static class ElGamal
-+    //     extends JDKKeyPairGenerator
-+    // {
-+    //     ElGamalKeyGenerationParameters  param;
-+    //     ElGamalKeyPairGenerator         engine = new ElGamalKeyPairGenerator();
-+    //     int                             strength = 1024;
-+    //     int                             certainty = 20;
-+    //     SecureRandom                    random = new SecureRandom();
-+    //     boolean                         initialised = false;
-+    //
-+    //     public ElGamal()
-+    //     {
-+    //         super("ElGamal");
-+    //     }
-+    //
-+    //     public void initialize(
-+    //         int             strength,
-+    //         SecureRandom    random)
-+    //     {
-+    //         this.strength = strength;
-+    //         this.random = random;
-+    //     }
-+    //
-+    //     public void initialize(
-+    //         AlgorithmParameterSpec  params,
-+    //         SecureRandom            random)
-+    //         throws InvalidAlgorithmParameterException
-+    //     {
-+    //         if (!(params instanceof ElGamalParameterSpec) && !(params instanceof DHParameterSpec))
-+    //         {
-+    //             throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec or an ElGamalParameterSpec");
-+    //         }
-+    //
-+    //         if (params instanceof ElGamalParameterSpec)
-+    //         {
-+    //             ElGamalParameterSpec     elParams = (ElGamalParameterSpec)params;
-+
-+    //             param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(elParams.getP(), elParams.getG()));
-+    //         }
-+    //         else
-+    //         {
-+    //             DHParameterSpec     dhParams = (DHParameterSpec)params;
-+    //
-+    //             param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(dhParams.getP(), dhParams.getG(), dhParams.getL()));
-+    //         }
-+    //
-+    //         engine.init(param);
-+    //         initialised = true;
-+    //     }
-+    //
-+    //     public KeyPair generateKeyPair()
-+    //     {
-+    //         if (!initialised)
-+    //         {
-+    //             ElGamalParametersGenerator   pGen = new ElGamalParametersGenerator();
-+    //
-+    //             pGen.init(strength, certainty, random);
-+    //             param = new ElGamalKeyGenerationParameters(random, pGen.generateParameters());
-+    //             engine.init(param);
-+    //             initialised = true;
-+    //         }
-+    //
-+    //         AsymmetricCipherKeyPair         pair = engine.generateKeyPair();
-+    //         ElGamalPublicKeyParameters      pub = (ElGamalPublicKeyParameters)pair.getPublic();
-+    //         ElGamalPrivateKeyParameters     priv = (ElGamalPrivateKeyParameters)pair.getPrivate();
-+    //
-+    //         return new KeyPair(new JCEElGamalPublicKey(pub),
-+    //                            new JCEElGamalPrivateKey(priv));
-+    //     }
-+    // }
-+    // END android-removed
-+
-+   // BEGIN android-removed
-+   //  public static class GOST3410
-+   //      extends JDKKeyPairGenerator
-+   //  {
-+   //      GOST3410KeyGenerationParameters param;
-+   //      GOST3410KeyPairGenerator        engine = new GOST3410KeyPairGenerator();
-+   //      GOST3410ParameterSpec           gost3410Params;
-+   //      int                             strength = 1024;
-+   //      SecureRandom                    random = null;
-+   //      boolean                         initialised = false;
-+   //
-+   //      public GOST3410()
-+   //      {
-+   //          super("GOST3410");
-+   //      }
-+   //
-+   //      public void initialize(
-+   //          int             strength,
-+   //          SecureRandom    random)
-+   //      {
-+   //          this.strength = strength;
-+   //          this.random = random;
-+   //      }
-+   //
-+   //      private void init(
-+   //          GOST3410ParameterSpec gParams,
-+   //          SecureRandom          random)
-+   //      {
-+   //          GOST3410PublicKeyParameterSetSpec spec = gParams.getPublicKeyParameters();
-+   //
-+   //          param = new GOST3410KeyGenerationParameters(random, new GOST3410Parameters(spec.getP(), spec.getQ(), spec.getA()));
-+   //
-+   //          engine.init(param);
-+   //
-+   //          initialised = true;
-+   //          gost3410Params = gParams;
-+   //      }
-+   //
-+   //      public void initialize(
-+   //          AlgorithmParameterSpec  params,
-+   //          SecureRandom            random)
-+   //          throws InvalidAlgorithmParameterException
-+   //      {
-+   //          if (!(params instanceof GOST3410ParameterSpec))
-+   //          {
-+   //              throw new InvalidAlgorithmParameterException("parameter object not a GOST3410ParameterSpec");
-+   //          }
-+   //
-+   //          init((GOST3410ParameterSpec)params, random);
-+   //      }
-+   //
-+   //      public KeyPair generateKeyPair()
-+   //      {
-+   //          if (!initialised)
-+   //          {
-+   //              init(new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()), new SecureRandom());
-+   //          }
-+   //         
-+   //          AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
-+   //          GOST3410PublicKeyParameters  pub = (GOST3410PublicKeyParameters)pair.getPublic();
-+   //          GOST3410PrivateKeyParameters priv = (GOST3410PrivateKeyParameters)pair.getPrivate();
-+   //
-+   //          return new KeyPair(new JDKGOST3410PublicKey(pub, gost3410Params), new JDKGOST3410PrivateKey(priv, gost3410Params));
-+   //      }
-+   // }
-+   // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyStore.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyStore.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyStore.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyStore.java	2012-07-27 18:48:00.031478939 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JDKKeyStore.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JDKKeyStore.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JDKKeyStore.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JDKKeyStore.java	2012-09-11 00:12:44.000000000 +0000
 @@ -39,7 +39,12 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -8083,15 +8916,7 @@
  import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
  import org.bouncycastle.crypto.io.DigestInputStream;
  import org.bouncycastle.crypto.io.DigestOutputStream;
-@@ -442,6 +447,7 @@
-         }
-         catch (Exception e)
-         {
-+
-             throw new IOException("Exception creating key: " + e.toString());
-         }
-     }
-@@ -497,7 +503,13 @@
+@@ -498,7 +503,13 @@
  
          if (entry == null)
          {
@@ -8106,7 +8931,7 @@
          }
  
          table.remove(alias);
-@@ -810,12 +822,16 @@
+@@ -817,12 +828,16 @@
          //
          // we only do an integrity check if the password is provided.
          //
@@ -8123,23 +8948,23 @@
 +            PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
 +            // END android-changed
              pbeGen.init(passKey, salt, iterationCount);
-             CipherParameters macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
-             Arrays.fill(passKey, (byte)0);
-@@ -866,9 +882,11 @@
+ 
+             CipherParameters macParams;
+@@ -884,9 +899,11 @@
          dOut.write(salt);
          dOut.writeInt(iterationCount);
  
 -        HMac                    hMac = new HMac(new SHA1Digest());
 +        // BEGIN android-changed
 +        HMac                    hMac = new HMac(new OpenSSLDigest.SHA1());
-         MacOutputStream         mOut = new MacOutputStream(dOut, hMac);
+         MacOutputStream         mOut = new MacOutputStream(hMac);
 -        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
 +        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
 +        // END android-changed
          byte[]                  passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
  
          pbeGen.init(passKey, salt, iterationCount);
-@@ -956,7 +974,9 @@
+@@ -974,7 +991,9 @@
              Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount);
              CipherInputStream cIn = new CipherInputStream(dIn, cipher);
  
@@ -8150,476 +8975,21 @@
              DigestInputStream  dgIn = new DigestInputStream(cIn, dig);
      
              this.loadStore(dgIn);
-@@ -996,8 +1016,9 @@
+@@ -1013,7 +1032,9 @@
              cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
      
              CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
--            DigestOutputStream  dgOut = new DigestOutputStream(cOut, new SHA1Digest());
--    
+-            DigestOutputStream  dgOut = new DigestOutputStream(new SHA1Digest());
 +            // BEGIN android-changed
-+            DigestOutputStream  dgOut = new DigestOutputStream(cOut, new OpenSSLDigest.SHA1());
++            DigestOutputStream  dgOut = new DigestOutputStream(new OpenSSLDigest.SHA1());
 +            // END android-changed
-             this.saveStore(dgOut);
      
-             Digest  dig = dgOut.getDigest();
-@@ -1009,5 +1030,5 @@
+             this.saveStore(new TeeOutputStream(cOut, dgOut));
      
-             cOut.close();
-         }
--    }
-+    }    
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKMessageDigest.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKMessageDigest.java	2012-07-27 18:48:00.031478939 +0000
-@@ -57,36 +57,38 @@
-         {
-             super(new SHA1Digest());
-         }
--
-+    
-         public Object clone()
-             throws CloneNotSupportedException
-         {
-             SHA1 d = (SHA1)super.clone();
-             d.digest = new SHA1Digest((SHA1Digest)digest);
--
--            return d;
--        }
--    }
--
--    static public class SHA224
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public SHA224()
--        {
--            super(new SHA224Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            SHA224 d = (SHA224)super.clone();
--            d.digest = new SHA224Digest((SHA224Digest)digest);
--
-+    
-             return d;
-         }
-     }
--
-+    
-+    // BEGIN android-removed
-+    // static public class SHA224
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public SHA224()
-+    //     {
-+    //         super(new SHA224Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         SHA224 d = (SHA224)super.clone();
-+    //         d.digest = new SHA224Digest((SHA224Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    // END android-removed
-+    
-     static public class SHA256
-         extends JDKMessageDigest
-         implements Cloneable
-@@ -95,13 +97,13 @@
-         {
-             super(new SHA256Digest());
-         }
--
-+    
-         public Object clone()
-             throws CloneNotSupportedException
-         {
-             SHA256 d = (SHA256)super.clone();
-             d.digest = new SHA256Digest((SHA256Digest)digest);
--
-+    
-             return d;
-         }
-     }
-@@ -144,43 +146,45 @@
-         }
-     }
- 
--    static public class MD2
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public MD2()
--        {
--            super(new MD2Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            MD2 d = (MD2)super.clone();
--            d.digest = new MD2Digest((MD2Digest)digest);
--
--            return d;
--        }
--    }
--
--    static public class MD4
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public MD4()
--        {
--            super(new MD4Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            MD4 d = (MD4)super.clone();
--            d.digest = new MD4Digest((MD4Digest)digest);
--
--            return d;
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class MD2
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public MD2()
-+    //     {
-+    //         super(new MD2Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         MD2 d = (MD2)super.clone();
-+    //         d.digest = new MD2Digest((MD2Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //
-+    // static public class MD4
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public MD4()
-+    //     {
-+    //         super(new MD4Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         MD4 d = (MD4)super.clone();
-+    //         d.digest = new MD4Digest((MD4Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    // END android-removed
- 
-     static public class MD5
-         extends JDKMessageDigest
-@@ -190,147 +194,149 @@
-         {
-             super(new MD5Digest());
-         }
--
-+   
-         public Object clone()
-             throws CloneNotSupportedException
-         {
-             MD5 d = (MD5)super.clone();
-             d.digest = new MD5Digest((MD5Digest)digest);
--
--            return d;
--        }
--    }
--
--    static public class RIPEMD128
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public RIPEMD128()
--        {
--            super(new RIPEMD128Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            RIPEMD128 d = (RIPEMD128)super.clone();
--            d.digest = new RIPEMD128Digest((RIPEMD128Digest)digest);
--
-+   
-             return d;
-         }
-     }
- 
--    static public class RIPEMD160
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public RIPEMD160()
--        {
--            super(new RIPEMD160Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            RIPEMD160 d = (RIPEMD160)super.clone();
--            d.digest = new RIPEMD160Digest((RIPEMD160Digest)digest);
--
--            return d;
--        }
--    }
--    
--    static public class RIPEMD256
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public RIPEMD256()
--        {
--            super(new RIPEMD256Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            RIPEMD256 d = (RIPEMD256)super.clone();
--            d.digest = new RIPEMD256Digest((RIPEMD256Digest)digest);
--
--            return d;
--        }
--    }
--    
--    static public class RIPEMD320
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public RIPEMD320()
--        {
--            super(new RIPEMD320Digest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            RIPEMD320 d = (RIPEMD320)super.clone();
--            d.digest = new RIPEMD320Digest((RIPEMD320Digest)digest);
--
--            return d;
--        }
--    }
--    
--    static public class Tiger
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public Tiger()
--        {
--            super(new TigerDigest());
--        }
--
--        public Object clone()
--            throws CloneNotSupportedException
--        {
--            Tiger d = (Tiger)super.clone();
--            d.digest = new TigerDigest((TigerDigest)digest);
--
--            return d;
--        }
--    }
--    
--    static public class GOST3411
--        extends JDKMessageDigest
--        implements Cloneable
--    {
--        public GOST3411()
--        {
--            super(new GOST3411Digest());
--        }
--    
--        public Object clone()
--        throws CloneNotSupportedException
--        {
--            GOST3411 d = (GOST3411)super.clone();
--            d.digest = new GOST3411Digest((GOST3411Digest)digest);
--
--            return d;
--        }
--    }
--    
--    static public class Whirlpool
--       extends JDKMessageDigest
--       implements Cloneable
--    {
--        public Whirlpool()
--        {
--            super(new WhirlpoolDigest());
--        }
--        
--        public Object clone()
--        throws CloneNotSupportedException
--        {
--            Whirlpool d = (Whirlpool)super.clone();
--            d.digest = new WhirlpoolDigest((WhirlpoolDigest)digest);
--            
--            return d;
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class RIPEMD128
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public RIPEMD128()
-+    //     {
-+    //         super(new RIPEMD128Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         RIPEMD128 d = (RIPEMD128)super.clone();
-+    //         d.digest = new RIPEMD128Digest((RIPEMD128Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //
-+    // static public class RIPEMD160
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public RIPEMD160()
-+    //     {
-+    //         super(new RIPEMD160Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         RIPEMD160 d = (RIPEMD160)super.clone();
-+    //         d.digest = new RIPEMD160Digest((RIPEMD160Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //   
-+    // static public class RIPEMD256
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public RIPEMD256()
-+    //     {
-+    //         super(new RIPEMD256Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         RIPEMD256 d = (RIPEMD256)super.clone();
-+    //         d.digest = new RIPEMD256Digest((RIPEMD256Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //   
-+    // static public class RIPEMD320
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public RIPEMD320()
-+    //     {
-+    //         super(new RIPEMD320Digest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         RIPEMD320 d = (RIPEMD320)super.clone();
-+    //         d.digest = new RIPEMD320Digest((RIPEMD320Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //   
-+    // static public class Tiger
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public Tiger()
-+    //     {
-+    //         super(new TigerDigest());
-+    //     }
-+    //
-+    //     public Object clone()
-+    //         throws CloneNotSupportedException
-+    //     {
-+    //         Tiger d = (Tiger)super.clone();
-+    //         d.digest = new TigerDigest((TigerDigest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //   
-+    // static public class GOST3411
-+    //     extends JDKMessageDigest
-+    //     implements Cloneable
-+    // {
-+    //     public GOST3411()
-+    //     {
-+    //         super(new GOST3411Digest());
-+    //     }
-+    //   
-+    //     public Object clone()
-+    //     throws CloneNotSupportedException
-+    //     {
-+    //         GOST3411 d = (GOST3411)super.clone();
-+    //         d.digest = new GOST3411Digest((GOST3411Digest)digest);
-+    //
-+    //         return d;
-+    //     }
-+    // }
-+    //   
-+    // static public class Whirlpool
-+    //    extends JDKMessageDigest
-+    //    implements Cloneable
-+    // {
-+    //     public Whirlpool()
-+    //     {
-+    //         super(new WhirlpoolDigest());
-+    //     }
-+    //       
-+    //     public Object clone()
-+    //     throws CloneNotSupportedException
-+    //     {
-+    //         Whirlpool d = (Whirlpool)super.clone();
-+    //         d.digest = new WhirlpoolDigest((WhirlpoolDigest)digest);
-+    //           
-+    //         return d;
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2012-07-27 18:48:00.031478939 +0000
-@@ -260,10 +260,13 @@
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2012-09-11 00:12:44.000000000 +0000
+@@ -261,10 +261,13 @@
              }
          }
  
@@ -8637,7 +9007,7 @@
      }
  
      /**
-@@ -438,6 +441,14 @@
+@@ -439,6 +442,14 @@
      
      public Date engineGetCreationDate(String alias) 
      {
@@ -8652,7 +9022,7 @@
          return new Date();
      }
  
-@@ -496,6 +507,11 @@
+@@ -497,6 +508,11 @@
          Certificate[]   chain) 
          throws KeyStoreException
      {
@@ -8664,7 +9034,7 @@
          if ((key instanceof PrivateKey) && (chain == null))
          {
              throw new KeyStoreException("no certificate chain for private key");
-@@ -507,12 +523,18 @@
+@@ -508,12 +524,18 @@
          }
  
          keys.put(alias, key);
@@ -8683,7 +9053,7 @@
      }
  
      public int engineSize() 
-@@ -1488,7 +1510,9 @@
+@@ -1489,7 +1511,9 @@
          {
              byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
  
@@ -8694,7 +9064,7 @@
              DigestInfo              dInfo = new DigestInfo(algId, res);
  
              mData = new MacData(dInfo, mSalt, itCount);
-@@ -1545,32 +1569,34 @@
+@@ -1546,32 +1570,34 @@
          }
      }
  
@@ -8712,7 +9082,7 @@
 -    {
 -        public DefPKCS12KeyStore()
 -        {
--            super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbewithSHAAnd40BitRC2_CBC);
+-            super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
 -        }
 -    }
 -
@@ -8739,7 +9109,7 @@
 +    // {
 +    //     public DefPKCS12KeyStore()
 +    //     {
-+    //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbewithSHAAnd40BitRC2_CBC);
++    //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
 +    //     }
 +    // }
 +    //
@@ -8755,16 +9125,18 @@
  
      private static class IgnoresCaseHashtable
      {
-@@ -1579,7 +1605,7 @@
+@@ -1580,7 +1606,9 @@
  
          public void put(String key, Object value)
          {
 -            String lower = Strings.toLowerCase(key);
++            // BEGIN android-changed
 +            String lower = (key == null) ? null : Strings.toLowerCase(key);
++            // END android-changed
              String k = (String)keys.get(lower);
              if (k != null)
              {
-@@ -1597,7 +1623,9 @@
+@@ -1598,7 +1626,9 @@
  
          public Object remove(String alias)
          {
@@ -8775,7 +9147,7 @@
              if (k == null)
              {
                  return null;
-@@ -1608,7 +1636,9 @@
+@@ -1609,7 +1639,9 @@
  
          public Object get(String alias)
          {
@@ -8786,149 +9158,9 @@
              if (k == null)
              {
                  return null;
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PBE.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PBE.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PBE.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PBE.java	2012-07-27 18:48:00.031478939 +0000
-@@ -7,12 +7,18 @@
- 
- import org.bouncycastle.crypto.CipherParameters;
- import org.bouncycastle.crypto.PBEParametersGenerator;
--import org.bouncycastle.crypto.digests.MD2Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.MD2Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.MD5Digest;
--import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// END android-removed
- import org.bouncycastle.crypto.digests.SHA1Digest;
- import org.bouncycastle.crypto.digests.SHA256Digest;
--import org.bouncycastle.crypto.digests.TigerDigest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.TigerDigest;
-+// END android-removed
- import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
- import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
- import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
-@@ -53,9 +59,11 @@
-             {
-                 switch (hash)
-                 {
--                case MD2:
--                    generator = new PKCS5S1ParametersGenerator(new MD2Digest());
--                    break;
-+                // BEGIN android-removed
-+                // case MD2:
-+                //     generator = new PKCS5S1ParametersGenerator(new MD2Digest());
-+                //     break;
-+                // END android-removed
-                 case MD5:
-                     generator = new PKCS5S1ParametersGenerator(new MD5Digest());
-                     break;
-@@ -74,21 +82,25 @@
-             {
-                 switch (hash)
-                 {
--                case MD2:
--                    generator = new PKCS12ParametersGenerator(new MD2Digest());
--                    break;
-+                // BEGIN android-removed
-+                // case MD2:
-+                //     generator = new PKCS12ParametersGenerator(new MD2Digest());
-+                //     break;
-+                // END android-removed
-                 case MD5:
-                     generator = new PKCS12ParametersGenerator(new MD5Digest());
-                     break;
-                 case SHA1:
-                     generator = new PKCS12ParametersGenerator(new SHA1Digest());
-                     break;
--                case RIPEMD160:
--                    generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
--                    break;
--                case TIGER:
--                    generator = new PKCS12ParametersGenerator(new TigerDigest());
--                    break;
-+                // BEGIN android-removed
-+                // case RIPEMD160:
-+                //     generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
-+                //     break;
-+                // case TIGER:
-+                //     generator = new PKCS12ParametersGenerator(new TigerDigest());
-+                //     break;
-+                // END android-removed
-                 case SHA256:
-                     generator = new PKCS12ParametersGenerator(new SHA256Digest());
-                     break;
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPath.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPath.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPath.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPath.java	2012-07-27 18:48:00.041479127 +0000
-@@ -33,7 +33,9 @@
- import org.bouncycastle.asn1.pkcs.ContentInfo;
- import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
- import org.bouncycastle.asn1.pkcs.SignedData;
--import org.bouncycastle.openssl.PEMWriter;
-+// BEGIN android-removed
-+// import org.bouncycastle.openssl.PEMWriter;
-+// END android-removed
- 
- /**
-  * CertPath implementation for X.509 certificates.
-@@ -295,27 +297,29 @@
-             return toDEREncoded(new ContentInfo(
-                     PKCSObjectIdentifiers.signedData, sd));
-         }
--        else if (encoding.equalsIgnoreCase("PEM"))
--        {
--            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
--            PEMWriter             pWrt = new PEMWriter(new OutputStreamWriter(bOut));
--
--            try
--            {
--                for (int i = 0; i != certificates.size(); i++)
--                {
--                    pWrt.writeObject(certificates.get(i));
--                }
--            
--                pWrt.close();
--            }
--            catch (Exception e)
--            {
--                throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
--            }
--
--            return bOut.toByteArray();
--        }
-+        // BEGIN android-removed
-+        // else if (encoding.equalsIgnoreCase("PEM"))
-+        // {
-+        //     ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-+        //     PEMWriter             pWrt = new PEMWriter(new OutputStreamWriter(bOut));
-+        //
-+        //     try
-+        //     {
-+        //         for (int i = 0; i != certificates.size(); i++)
-+        //         {
-+        //             pWrt.writeObject(certificates.get(i));
-+        //         }
-+        //     
-+        //         pWrt.close();
-+        //     }
-+        //     catch (Exception e)
-+        //     {
-+        //         throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
-+        //     }
-+        //
-+        //     return bOut.toByteArray();
-+        // }
-+        // END android-removed
-         else
-         {
-             throw new CertificateEncodingException("unsupported encoding: " + encoding);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2012-07-27 18:48:00.031478939 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2012-09-11 00:12:44.000000000 +0000
 @@ -1,5 +1,8 @@
  package org.bouncycastle.jce.provider;
  
@@ -8938,15 +9170,7 @@
  import java.security.InvalidAlgorithmParameterException;
  import java.security.PublicKey;
  import java.security.cert.CertPath;
-@@ -13,6 +16,7 @@
- import java.security.cert.TrustAnchor;
- import java.security.cert.X509Certificate;
- import java.util.ArrayList;
-+import java.util.Arrays;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.List;
-@@ -33,6 +37,9 @@
+@@ -33,6 +36,9 @@
  public class PKIXCertPathValidatorSpi
          extends CertPathValidatorSpi
  {
@@ -8956,7 +9180,7 @@
  
      public CertPathValidatorResult engineValidate(
              CertPath certPath,
-@@ -75,6 +82,22 @@
+@@ -75,6 +81,22 @@
          {
              throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
          }
@@ -8979,7 +9203,7 @@
  
          //
          // (b)
-@@ -251,6 +274,15 @@
+@@ -251,6 +273,15 @@
  
          for (index = certs.size() - 1; index >= 0; index--)
          {
@@ -8995,9 +9219,9 @@
              // try
              // {
              //
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2012-07-27 18:48:00.031478939 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2012-09-11 00:12:44.000000000 +0000
 @@ -1533,7 +1533,9 @@
          for (Enumeration e = permitted.getObjects(); e.hasMoreElements();)
          {
@@ -9009,143 +9233,11 @@
              if (subtreesMap.get(tagNo) == null)
              {
                  subtreesMap.put(tagNo, new HashSet());
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java bcprov-jdk16-146/org/bouncycastle/jce/provider/WrapCipherSpi.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/WrapCipherSpi.java	2012-07-27 18:48:00.031478939 +0000
-@@ -22,8 +22,10 @@
- import javax.crypto.ShortBufferException;
- import javax.crypto.spec.IvParameterSpec;
- import javax.crypto.spec.PBEParameterSpec;
--import javax.crypto.spec.RC2ParameterSpec;
--import javax.crypto.spec.RC5ParameterSpec;
-+// BEGIN android-removed
-+// import javax.crypto.spec.RC2ParameterSpec;
-+// import javax.crypto.spec.RC5ParameterSpec;
-+// END android-removed
- import javax.crypto.spec.SecretKeySpec;
- 
- import org.bouncycastle.asn1.ASN1InputStream;
-@@ -36,7 +38,9 @@
- import org.bouncycastle.crypto.CipherParameters;
- import org.bouncycastle.crypto.InvalidCipherTextException;
- import org.bouncycastle.crypto.Wrapper;
--import org.bouncycastle.crypto.engines.RC2WrapEngine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.RC2WrapEngine;
-+// END android-removed
- import org.bouncycastle.crypto.params.KeyParameter;
- import org.bouncycastle.crypto.params.ParametersWithIV;
- 
-@@ -50,8 +54,10 @@
-                                     {
-                                         IvParameterSpec.class,
-                                         PBEParameterSpec.class,
--                                        RC2ParameterSpec.class,
--                                        RC5ParameterSpec.class
-+                                        // BEGIN android-removed
-+                                        // RC2ParameterSpec.class,
-+                                        // RC5ParameterSpec.class
-+                                        // END android-removed
-                                     };
- 
-     protected int                     pbeType = PKCS12;
-@@ -263,16 +269,19 @@
-         return null;
-     }
- 
-+    // BEGIN android-changed
-+    // added ShortBufferException to throws statement
-     protected int engineDoFinal(
-         byte[]  input,
-         int     inputOffset,
-         int     inputLen,
-         byte[]  output,
-         int     outputOffset)
--        throws IllegalBlockSizeException, BadPaddingException
-+        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
-     {
-         return 0;
-     }
-+    // END android-changed
- 
-     protected byte[] engineWrap(
-         Key     key)
-@@ -305,7 +314,12 @@
-         byte[]  wrappedKey,
-         String  wrappedKeyAlgorithm,
-         int     wrappedKeyType)
--    throws InvalidKeyException
-+    // BEGIN android-removed
-+    // throws InvalidKeyException
-+    // END android-removed
-+    // BEGIN android-added
-+    throws InvalidKeyException, NoSuchAlgorithmException
-+    // END android-added
-     {
-         byte[] encoded;
-         try
-@@ -356,10 +370,12 @@
-                 {
-                     privKey = new JCEECPrivateKey(in);
-                 }
--                else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
--                {
--                    privKey = new JDKGOST3410PrivateKey(in);
--                }
-+                // BEGIN android-removed
-+                // else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
-+                // {
-+                //     privKey = new JDKGOST3410PrivateKey(in);
-+                // }
-+                // END android-removed
-                 else if (oid.equals(X9ObjectIdentifiers.id_dsa))
-                 {
-                     privKey = new JDKDSAPrivateKey(in);
-@@ -403,10 +419,12 @@
-             {
-                 throw new InvalidKeyException("Unknown key type " + e.getMessage());
-             }
--            catch (NoSuchAlgorithmException e)
--            {
--                throw new InvalidKeyException("Unknown key type " + e.getMessage());
--            }
-+            // BEGIN android-removed
-+            // catch (NoSuchAlgorithmException e)
-+            // {
-+            //     throw new InvalidKeyException("Unknown key type " + e.getMessage());
-+            // }
-+            // END android-removed
-             catch (InvalidKeySpecException e2)
-             {
-                 throw new InvalidKeyException("Unknown key type " + e2.getMessage());
-@@ -420,12 +438,14 @@
-     // classes that inherit directly from us
-     //
- 
--    public static class RC2Wrap
--        extends WrapCipherSpi
--    {
--        public RC2Wrap()
--        {
--            super(new RC2WrapEngine());
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class RC2Wrap
-+    //     extends WrapCipherSpi
-+    // {
-+    //     public RC2Wrap()
-+    //     {
-+    //         super(new RC2WrapEngine());
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk16-146/org/bouncycastle/jce/provider/X509CertificateObject.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/X509CertificateObject.java	2012-07-27 18:48:00.031478939 +0000
-@@ -520,12 +520,20 @@
-         return JDKKeyFactory.createPublicKeyFromPublicKeyInfo(c.getSubjectPublicKeyInfo());
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/X509CertificateObject.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/X509CertificateObject.java	2012-09-11 00:12:44.000000000 +0000
+@@ -544,12 +544,20 @@
+         }
      }
  
 +    // BEGIN android-changed
@@ -9156,28 +9248,19 @@
      {
          try
          {
--            return c.getEncoded(ASN1Encodable.DER);
+-            return c.getEncoded(ASN1Encoding.DER);
 +            // BEGIN android-changed
 +            if (encoded == null) {
-+                encoded = c.getEncoded(ASN1Encodable.DER);
++                encoded = c.getEncoded(ASN1Encoding.DER);
 +            }
 +            return encoded;
 +            // END android-changed
          }
          catch (IOException e)
          {
-@@ -711,7 +719,7 @@
-     {
-         Signature   signature;
-         String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
--        
-+
-         try
-         {
-             signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk16-146/org/bouncycastle/jce/provider/X509SignatureUtil.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/X509SignatureUtil.java	2012-07-27 18:48:00.031478939 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk15on-147/org/bouncycastle/jce/provider/X509SignatureUtil.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/X509SignatureUtil.java	2012-09-11 00:12:44.000000000 +0000
 @@ -25,7 +25,9 @@
  
  class X509SignatureUtil
@@ -9268,1564 +9351,21 @@
          else
          {
              return digestAlgOID.getId();            
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/EC.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/EC.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/EC.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/EC.java	2012-07-27 18:48:00.031478939 +0000
-@@ -4,8 +4,10 @@
- 
- import org.bouncycastle.asn1.DERObjectIdentifier;
- import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
--import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk15on-147/org/bouncycastle/x509/X509Util.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/x509/X509Util.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/x509/X509Util.java	2012-09-11 00:12:44.000000000 +0000
+@@ -30,7 +30,9 @@
+ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
 -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
 +// BEGIN android-removed
-+// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
 +// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
 +// END android-removed
+ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
- 
- public class EC
-@@ -16,39 +18,49 @@
-         public Mappings()
-         {
-             put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
--            put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
--            put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
--            put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
--            put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
-+            // BEGIN android-removed
-+            // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
-+            // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
-+            // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
-+            // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
-+            // END android-removed
- 
-             put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
--            put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
--            put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
--            put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
--            put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
-+            // BEGIN android-removed
-+            // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
-+            // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
-+            // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
-+            // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
-+            // END android-removed
-             put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
-             // TODO Should this be an alias for ECDH?
-             put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
--            put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
--
--            put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
--            put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
--            put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
--            put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
-+            // BEGIN android-removed
-+            // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-+            //
-+            // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
-+            // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
-+            // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
-+            // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
-+            // END android-removed
- 
-             put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
--            put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
--            put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
--            put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
--            put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
--            put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
-+            // BEGIN android-removed
-+            // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
-+            // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-+            // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
-+            // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-+            // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
-+            // END android-removed
-             // TODO Should this be an alias for ECDH?
-             put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
--            put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
--
--            put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
--            put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
--            put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
-+            // BEGIN android-removed
-+            // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-+            //
-+            // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
-+            // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
-+            // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
-+            // END android-removed
- 
-             put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
-             put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
-@@ -60,23 +72,27 @@
-             put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
-             put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
-             put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
--            put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
--
--            addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-+            // BEGIN android-removed
-+            // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
-+            //
-+            // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-+            // END android-removed
-             addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
-             addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
-             addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
--            addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
--
--            put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
--            put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
--            put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
--            put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
--            put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
--
--            addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
--            addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
--            addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-+            // BEGIN android-removed
-+            // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
-+            //
-+            // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
-+            // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
-+            // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
-+            // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
-+            // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
-+            //
-+            // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
-+            // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
-+            // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-+            // END android-removed
-         }
- 
-         private void addSignatureAlgorithm(
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2012-07-27 18:48:00.031478939 +0000
-@@ -1,10 +1,14 @@
- package org.bouncycastle.jce.provider.asymmetric.ec;
- 
- import org.bouncycastle.asn1.DERObjectIdentifier;
--import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-+// END android-removed
- 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.params.AsymmetricKeyParameter;
-@@ -167,14 +171,16 @@
-             {
-                 oid = NISTNamedCurves.getOID(name);
-             }
--            if (oid == null)
--            {
--                oid = TeleTrusTNamedCurves.getOID(name);
--            }
--            if (oid == null)
--            {
--                oid = ECGOST3410NamedCurves.getOID(name);
--            }
-+            // BEGIN android-removed
-+            // if (oid == null)
-+            // {
-+            //     oid = TeleTrusTNamedCurves.getOID(name);
-+            // }
-+            // if (oid == null)
-+            // {
-+            //     oid = ECGOST3410NamedCurves.getOID(name);
-+            // }
-+            // END android-removed
-         }
- 
-         return oid;
-@@ -192,10 +198,12 @@
-             {
-                 params = NISTNamedCurves.getByOID(oid);
-             }
--            if (params == null)
--            {
--                params = TeleTrusTNamedCurves.getByOID(oid);
--            }
-+            // BEGIN android-removed
-+            // if (params == null)
-+            // {
-+            //     params = TeleTrusTNamedCurves.getByOID(oid);
-+            // }
-+            // END android-removed
-         }
- 
-         return params;
-@@ -213,14 +221,16 @@
-             {
-                 name = NISTNamedCurves.getName(oid);
-             }
--            if (name == null)
--            {
--                name = TeleTrusTNamedCurves.getName(oid);
--            }
--            if (name == null)
--            {
--                name = ECGOST3410NamedCurves.getName(oid);
--            }
-+            // BEGIN android-removed
-+            // if (name == null)
-+            // {
-+            //     name = TeleTrusTNamedCurves.getName(oid);
-+            // }
-+            // if (name == null)
-+            // {
-+            //     name = ECGOST3410NamedCurves.getName(oid);
-+            // }
-+            // END android-removed
-         }
- 
-         return name;
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2012-07-27 18:48:00.031478939 +0000
-@@ -24,20 +24,26 @@
- import org.bouncycastle.crypto.CipherParameters;
- import org.bouncycastle.crypto.DerivationFunction;
- import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
--import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
--import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
--import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
--import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
-+// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
-+// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
-+// import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
-+// END android-removed
- import org.bouncycastle.crypto.digests.SHA1Digest;
- import org.bouncycastle.crypto.params.ECDomainParameters;
- import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
- import org.bouncycastle.crypto.params.ECPublicKeyParameters;
--import org.bouncycastle.crypto.params.MQVPrivateParameters;
--import org.bouncycastle.crypto.params.MQVPublicParameters;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.params.MQVPrivateParameters;
-+// import org.bouncycastle.crypto.params.MQVPublicParameters;
-+// END android-removed
- import org.bouncycastle.jce.interfaces.ECPrivateKey;
- import org.bouncycastle.jce.interfaces.ECPublicKey;
--import org.bouncycastle.jce.interfaces.MQVPrivateKey;
--import org.bouncycastle.jce.interfaces.MQVPublicKey;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
-+// import org.bouncycastle.jce.interfaces.MQVPublicKey;
-+// END android-removed
- 
- /**
-  * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
-@@ -53,9 +59,11 @@
- 
-     static
-     {
--        Integer i128 = new Integer(128);
--        Integer i192 = new Integer(192);
--        Integer i256 = new Integer(256);
-+        // BEGIN android-changed
-+        Integer i128 = Integer.valueOf(128);
-+        Integer i192 = Integer.valueOf(192);
-+        Integer i256 = Integer.valueOf(256);
-+        // END android-changed
- 
-         algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
-         algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
-@@ -70,7 +78,9 @@
-     private BigInteger             result;
-     private ECDomainParameters     parameters;
-     private BasicAgreement         agreement;
--    private DerivationFunction     kdf;
-+    // BEGIN android-removed
-+    // private DerivationFunction     kdf;
-+    // END android-removed
- 
-     private byte[] bigIntToBytes(
-         BigInteger    r)
-@@ -85,7 +95,9 @@
-     {
-         this.kaAlgorithm = kaAlgorithm;
-         this.agreement = agreement;
--        this.kdf = kdf;
-+        // BEGIN android-removed
-+        // this.kdf = kdf;
-+        // END android-removed
-     }
- 
-     protected Key engineDoPhase(
-@@ -104,25 +116,27 @@
-         }
- 
-         CipherParameters pubKey;        
--        if (agreement instanceof ECMQVBasicAgreement)
--        {
--            if (!(key instanceof MQVPublicKey))
--            {
--                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
--                    + getSimpleName(MQVPublicKey.class) + " for doPhase");
--            }
--
--            MQVPublicKey mqvPubKey = (MQVPublicKey)key;
--            ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
--                ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
--            ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
--                ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
--
--            pubKey = new MQVPublicParameters(staticKey, ephemKey);
--
--            // TODO Validate that all the keys are using the same parameters?
--        }
--        else
-+        // BEGIN android-removed
-+        // if (agreement instanceof ECMQVBasicAgreement)
-+        // {
-+        //     if (!(key instanceof MQVPublicKey))
-+        //     {
-+        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
-+        //             + getSimpleName(MQVPublicKey.class) + " for doPhase");
-+        //     }
-+        //
-+        //     MQVPublicKey mqvPubKey = (MQVPublicKey)key;
-+        //     ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
-+        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
-+        //     ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
-+        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
-+        //
-+        //     pubKey = new MQVPublicParameters(staticKey, ephemKey);
-+        //
-+        //     // TODO Validate that all the keys are using the same parameters?
-+        // }
-+        // else
-+        // END android-removed
-         {
-             if (!(key instanceof ECPublicKey))
-             {
-@@ -143,11 +157,13 @@
-     protected byte[] engineGenerateSecret()
-         throws IllegalStateException
-     {
--        if (kdf != null)
--        {
--            throw new UnsupportedOperationException(
--                "KDF can only be used when algorithm is known");
--        }
-+        // BEGIN android-removed
-+        // if (kdf != null)
-+        // {
-+        //     throw new UnsupportedOperationException(
-+        //         "KDF can only be used when algorithm is known");
-+        // }
-+        // END android-removed
- 
-         return bigIntToBytes(result);
-     }
-@@ -175,23 +191,25 @@
-     {
-         byte[] secret = bigIntToBytes(result);
- 
--        if (kdf != null)
--        {
--            if (!algorithms.containsKey(algorithm))
--            {
--                throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
--            }
--            
--            int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
--
--            DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
--
--            byte[] keyBytes = new byte[keySize / 8];
--            kdf.init(params);
--            kdf.generateBytes(keyBytes, 0, keyBytes.length);
--            secret = keyBytes;
--        }
--        else
-+        // BEGIN android-removed
-+        // if (kdf != null)
-+        // {
-+        //     if (!algorithms.containsKey(algorithm))
-+        //     {
-+        //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
-+        //     }
-+        //  
-+        //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
-+        //
-+        //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
-+        //
-+        //     byte[] keyBytes = new byte[keySize / 8];
-+        //     kdf.init(params);
-+        //     kdf.generateBytes(keyBytes, 0, keyBytes.length);
-+        //     secret = keyBytes;
-+        // }
-+        // else
-+        // END android-removed
-         {
-             // TODO Should we be ensuring the key is the right length?
-         }
-@@ -219,35 +237,37 @@
-     private void initFromKey(Key key)
-         throws InvalidKeyException
-     {
--        if (agreement instanceof ECMQVBasicAgreement)
--        {
--            if (!(key instanceof MQVPrivateKey))
--            {
--                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
--                    + getSimpleName(MQVPrivateKey.class) + " for initialisation");
--            }
--
--            MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
--            ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
--                ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
--            ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
--                ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
--
--            ECPublicKeyParameters ephemPubKey = null;
--            if (mqvPrivKey.getEphemeralPublicKey() != null)
--            {
--                ephemPubKey = (ECPublicKeyParameters)
--                    ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
--            }
--
--            MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
--            this.parameters = staticPrivKey.getParameters();
--
--            // TODO Validate that all the keys are using the same parameters?
--
--            agreement.init(localParams);
--        }
--        else
-+        // BEGIN android-removed
-+        // if (agreement instanceof ECMQVBasicAgreement)
-+        // {
-+        //     if (!(key instanceof MQVPrivateKey))
-+        //     {
-+        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
-+        //             + getSimpleName(MQVPrivateKey.class) + " for initialisation");
-+        //     }
-+        //
-+        //     MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
-+        //     ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
-+        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
-+        //     ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
-+        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
-+        //
-+        //     ECPublicKeyParameters ephemPubKey = null;
-+        //     if (mqvPrivKey.getEphemeralPublicKey() != null)
-+        //     {
-+        //         ephemPubKey = (ECPublicKeyParameters)
-+        //             ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
-+        //     }
-+        //
-+        //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
-+        //     this.parameters = staticPrivKey.getParameters();
-+        //
-+        //     // TODO Validate that all the keys are using the same parameters?
-+        //
-+        //     agreement.init(localParams);
-+        // }
-+        // else
-+        // END android-removed
-         {
-             if (!(key instanceof ECPrivateKey))
-             {
-@@ -278,39 +298,41 @@
-         }
-     }
- 
--    public static class DHC
--        extends KeyAgreement
--    {
--        public DHC()
--        {
--            super("ECDHC", new ECDHCBasicAgreement(), null);
--        }
--    }
--
--    public static class MQV
--        extends KeyAgreement
--    {
--        public MQV()
--        {
--            super("ECMQV", new ECMQVBasicAgreement(), null);
--        }
--    }
--
--    public static class DHwithSHA1KDF
--        extends KeyAgreement
--    {
--        public DHwithSHA1KDF()
--        {
--            super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
--        }
--    }
--
--    public static class MQVwithSHA1KDF
--        extends KeyAgreement
--    {
--        public MQVwithSHA1KDF()
--        {
--            super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class DHC
-+    //     extends KeyAgreement
-+    // {
-+    //     public DHC()
-+    //     {
-+    //         super("ECDHC", new ECDHCBasicAgreement(), null);
-+    //     }
-+    // }
-+    //
-+    // public static class MQV
-+    //     extends KeyAgreement
-+    // {
-+    //     public MQV()
-+    //     {
-+    //         super("ECMQV", new ECMQVBasicAgreement(), null);
-+    //     }
-+    // }
-+    //
-+    // public static class DHwithSHA1KDF
-+    //     extends KeyAgreement
-+    // {
-+    //     public DHwithSHA1KDF()
-+    //     {
-+    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
-+    //     }
-+    // }
-+    //
-+    // public static class MQVwithSHA1KDF
-+    //     extends KeyAgreement
-+    // {
-+    //     public MQVwithSHA1KDF()
-+    //     {
-+    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2012-07-27 18:48:00.031478939 +0000
-@@ -10,10 +10,14 @@
- import java.util.Hashtable;
- 
- import org.bouncycastle.asn1.DERObjectIdentifier;
--import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-+// END android-removed
- 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;
-@@ -56,13 +60,15 @@
-         static {
-             ecParameters = new Hashtable();
- 
--            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
--            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
--            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
--
--            ecParameters.put(new Integer(224), new ECGenParameterSpec("P-224"));
--            ecParameters.put(new Integer(384), new ECGenParameterSpec("P-384"));
--            ecParameters.put(new Integer(521), new ECGenParameterSpec("P-521"));
-+            // BEGIN android-changed
-+            ecParameters.put(Integer.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
-+            ecParameters.put(Integer.valueOf(239), new ECGenParameterSpec("prime239v1"));
-+            ecParameters.put(Integer.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
-+
-+            ecParameters.put(Integer.valueOf(224), new ECGenParameterSpec("P-224"));
-+            ecParameters.put(Integer.valueOf(384), new ECGenParameterSpec("P-384"));
-+            ecParameters.put(Integer.valueOf(521), new ECGenParameterSpec("P-521"));
-+            // END android-changed
-         }
- 
-         public EC()
-@@ -83,8 +89,16 @@
-             SecureRandom    random)
-         {
-             this.strength = strength;
-+            // BEGIN android-added
-+            if (random != null) {
-+            // END android-added
-             this.random = random;
--            this.ecParams = ecParameters.get(new Integer(strength));
-+            // BEGIN android-added
-+            }
-+            // END android-added
-+            // BEGIN android-changed
-+            this.ecParams = ecParameters.get(Integer.valueOf(strength));
-+            // END android-changed
- 
-             if (ecParams != null)
-             {
-@@ -108,6 +122,11 @@
-             SecureRandom            random)
-             throws InvalidAlgorithmParameterException
-         {
-+            // BEGIN android-added
-+            if (random == null) {
-+                random = this.random;
-+            }
-+            // END android-added
-             if (params instanceof ECParameterSpec)
-             {
-                 ECParameterSpec p = (ECParameterSpec)params;
-@@ -135,23 +154,25 @@
-             {
-                 final String curveName = ((ECGenParameterSpec)params).getName();
- 
--                if (this.algorithm.equals("ECGOST3410"))
--                {
--                    ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(curveName);
--                    if (ecP == null)
--                    {
--                        throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
--                    }
--
--                    this.ecParams = new ECNamedCurveSpec(
--                                                    curveName,
--                                                    ecP.getCurve(),
--                                                    ecP.getG(),
--                                                    ecP.getN(),
--                                                    ecP.getH(),
--                                                    ecP.getSeed());
--                }
--                else
-+                // BEGIN android-removed
-+                // if (this.algorithm.equals("ECGOST3410"))
-+                // {
-+                //     ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(curveName);
-+                //     if (ecP == null)
-+                //     {
-+                //         throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
-+                //     }
-+                //
-+                //     this.ecParams = new ECNamedCurveSpec(
-+                //                                     curveName,
-+                //                                     ecP.getCurve(),
-+                //                                     ecP.getG(),
-+                //                                     ecP.getN(),
-+                //                                     ecP.getH(),
-+                //                                     ecP.getSeed());
-+                // }
-+                // else
-+                // END android-removed
-                 {
-                     X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
-                     if (ecP == null)
-@@ -161,10 +182,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)
-@@ -180,10 +203,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);
-@@ -239,7 +264,15 @@
-         {
-             if (!initialised)
-             {
--                throw new IllegalStateException("EC Key Pair Generator not initialised");
-+                // BEGIN android-removed
-+                // throw new IllegalStateException("EC Key Pair Generator not initialised");
-+                // END android-removed
-+                // BEGIN android-added
-+                /*
-+                 * KeyPairGenerator documentation says that a default initialization must be provided
-+                 */
-+                initialize(192, random);
-+                // END android-added
-             }
- 
-             AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
-@@ -279,14 +312,16 @@
-         }
-     }
- 
--    public static class ECGOST3410
--        extends EC
--    {
--        public ECGOST3410()
--        {
--            super("ECGOST3410");
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class ECGOST3410
-+    //     extends EC
-+    // {
-+    //     public ECGOST3410()
-+    //     {
-+    //         super("ECGOST3410");
-+    //     }
-+    // }
-+    // END android-removed
- 
-     public static class ECDH
-         extends EC
-@@ -314,4 +349,4 @@
-             super("ECMQV");
-         }
-     }
--}
-\ No newline at end of file
-+}
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2012-07-27 18:48:00.031478939 +0000
-@@ -18,15 +18,21 @@
- import org.bouncycastle.crypto.DSA;
- import org.bouncycastle.crypto.Digest;
- import org.bouncycastle.crypto.digests.NullDigest;
--import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-+// 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.SHA256Digest;
- import org.bouncycastle.crypto.digests.SHA384Digest;
- import org.bouncycastle.crypto.digests.SHA512Digest;
- import org.bouncycastle.crypto.params.ParametersWithRandom;
- import org.bouncycastle.crypto.signers.ECDSASigner;
--import org.bouncycastle.crypto.signers.ECNRSigner;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.signers.ECNRSigner;
-+// END android-removed
- import org.bouncycastle.jce.interfaces.ECKey;
- import org.bouncycastle.jce.provider.DSABase;
- import org.bouncycastle.jce.provider.DSAEncoder;
-@@ -122,14 +128,16 @@
-         }
-     }
- 
--    static public class ecDSA224
--        extends Signature
--    {
--        public ecDSA224()
--        {
--            super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class ecDSA224
-+    //     extends Signature
-+    // {
-+    //     public ecDSA224()
-+    //     {
-+    //         super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    // END android-removed
- 
-     static public class ecDSA256
-         extends Signature
-@@ -158,86 +166,88 @@
-         }
-     }
- 
--    static public class ecDSARipeMD160
--        extends Signature
--    {
--        public ecDSARipeMD160()
--        {
--            super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
--        }
--    }
--
--    static public class ecNR
--        extends Signature
--    {
--        public ecNR()
--        {
--            super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
--        }
--    }
--
--    static public class ecNR224
--        extends Signature
--    {
--        public ecNR224()
--        {
--            super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
--        }
--    }
--
--    static public class ecNR256
--        extends Signature
--    {
--        public ecNR256()
--        {
--            super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
--        }
--    }
--
--    static public class ecNR384
--        extends Signature
--    {
--        public ecNR384()
--        {
--            super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
--        }
--    }
--
--    static public class ecNR512
--        extends Signature
--    {
--        public ecNR512()
--        {
--            super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
--        }
--    }
--
--    static public class ecCVCDSA
--        extends Signature
--    {
--        public ecCVCDSA()
--        {
--            super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
--        }
--    }
--
--    static public class ecCVCDSA224
--        extends Signature
--    {
--        public ecCVCDSA224()
--        {
--            super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
--        }
--    }
--
--    static public class ecCVCDSA256
--        extends Signature
--    {
--        public ecCVCDSA256()
--        {
--            super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class ecDSARipeMD160
-+    //     extends Signature
-+    // {
-+    //     public ecDSARipeMD160()
-+    //     {
-+    //         super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecNR
-+    //     extends Signature
-+    // {
-+    //     public ecNR()
-+    //     {
-+    //         super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecNR224
-+    //     extends Signature
-+    // {
-+    //     public ecNR224()
-+    //     {
-+    //         super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecNR256
-+    //     extends Signature
-+    // {
-+    //     public ecNR256()
-+    //     {
-+    //         super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecNR384
-+    //     extends Signature
-+    // {
-+    //     public ecNR384()
-+    //     {
-+    //         super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecNR512
-+    //     extends Signature
-+    // {
-+    //     public ecNR512()
-+    //     {
-+    //         super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecCVCDSA
-+    //     extends Signature
-+    // {
-+    //     public ecCVCDSA()
-+    //     {
-+    //         super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecCVCDSA224
-+    //     extends Signature
-+    // {
-+    //     public ecCVCDSA224()
-+    //     {
-+    //         super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
-+    //     }
-+    // }
-+    //
-+    // static public class ecCVCDSA256
-+    //     extends Signature
-+    // {
-+    //     public ecCVCDSA256()
-+    //     {
-+    //         super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
-+    //     }
-+    // }
-+    // END android-removed
- 
-     private static class StdDSAEncoder
-         implements DSAEncoder
-@@ -331,4 +341,4 @@
-             return sig;
-         }
-     }
--}
-\ No newline at end of file
-+}
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/AES.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/AES.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/AES.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/AES.java	2012-07-27 18:48:00.031478939 +0000
-@@ -13,8 +13,10 @@
- import org.bouncycastle.crypto.CipherKeyGenerator;
- import org.bouncycastle.crypto.engines.AESFastEngine;
- import org.bouncycastle.crypto.engines.AESWrapEngine;
--import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
--import org.bouncycastle.crypto.macs.CMac;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-+// import org.bouncycastle.crypto.macs.CMac;
-+// END android-removed
- import org.bouncycastle.crypto.modes.CBCBlockCipher;
- import org.bouncycastle.crypto.modes.CFBBlockCipher;
- import org.bouncycastle.crypto.modes.OFBBlockCipher;
-@@ -41,41 +43,43 @@
-         }
-     }
- 
--    public static class CBC
--       extends JCEBlockCipher
--    {
--        public CBC()
--        {
--            super(new CBCBlockCipher(new AESFastEngine()), 128);
--        }
--    }
--
--    static public class CFB
--        extends JCEBlockCipher
--    {
--        public CFB()
--        {
--            super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
--        }
--    }
--
--    static public class OFB
--        extends JCEBlockCipher
--    {
--        public OFB()
--        {
--            super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
--        }
--    }
--
--    public static class AESCMAC
--        extends JCEMac
--    {
--        public AESCMAC()
--        {
--            super(new CMac(new AESFastEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class CBC
-+    //    extends JCEBlockCipher
-+    // {
-+    //     public CBC()
-+    //     {
-+    //         super(new CBCBlockCipher(new AESFastEngine()), 128);
-+    //     }
-+    // }
-+    //
-+    // static public class CFB
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public CFB()
-+    //     {
-+    //         super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
-+    //     }
-+    // }
-+    //
-+    // static public class OFB
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public OFB()
-+    //     {
-+    //         super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
-+    //     }
-+    // }
-+    //
-+    // public static class AESCMAC
-+    //     extends JCEMac
-+    // {
-+    //     public AESCMAC()
-+    //     {
-+    //         super(new CMac(new AESFastEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- 
-     static public class Wrap
-         extends WrapCipherSpi
-@@ -86,14 +90,16 @@
-         }
-     }
- 
--    public static class RFC3211Wrap
--        extends WrapCipherSpi
--    {
--        public RFC3211Wrap()
--        {
--            super(new RFC3211WrapEngine(new AESFastEngine()), 16);
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class RFC3211Wrap
-+    //     extends WrapCipherSpi
-+    // {
-+    //     public RFC3211Wrap()
-+    //     {
-+    //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
-+    //     }
-+    // }
-+    // END android-removed
- 
-     public static class KeyGen
-         extends JCEKeyGenerator
-@@ -109,70 +115,72 @@
-         }
-     }
- 
--    public static class KeyGen128
--        extends KeyGen
--    {
--        public KeyGen128()
--        {
--            super(128);
--        }
--    }
--
--    public static class KeyGen192
--        extends KeyGen
--    {
--        public KeyGen192()
--        {
--            super(192);
--        }
--    }
--
--    public static class KeyGen256
--        extends KeyGen
--    {
--        public KeyGen256()
--        {
--            super(256);
--        }
--    }
--
--    public static class AlgParamGen
--        extends JDKAlgorithmParameterGenerator
--    {
--        protected void engineInit(
--            AlgorithmParameterSpec genParamSpec,
--            SecureRandom random)
--            throws InvalidAlgorithmParameterException
--        {
--            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
--        }
--
--        protected AlgorithmParameters engineGenerateParameters()
--        {
--            byte[]  iv = new byte[16];
--
--            if (random == null)
--            {
--                random = new SecureRandom();
--            }
--
--            random.nextBytes(iv);
--
--            AlgorithmParameters params;
--
--            try
--            {
--                params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
--                params.init(new IvParameterSpec(iv));
--            }
--            catch (Exception e)
--            {
--                throw new RuntimeException(e.getMessage());
--            }
--
--            return params;
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class KeyGen128
-+    //     extends KeyGen
-+    // {
-+    //     public KeyGen128()
-+    //     {
-+    //         super(128);
-+    //     }
-+    // }
-+    //
-+    // public static class KeyGen192
-+    //     extends KeyGen
-+    // {
-+    //     public KeyGen192()
-+    //     {
-+    //         super(192);
-+    //     }
-+    // }
-+    //
-+    // public static class KeyGen256
-+    //     extends KeyGen
-+    // {
-+    //     public KeyGen256()
-+    //     {
-+    //         super(256);
-+    //     }
-+    // }
-+    //
-+    // public static class AlgParamGen
-+    //     extends JDKAlgorithmParameterGenerator
-+    // {
-+    //     protected void engineInit(
-+    //         AlgorithmParameterSpec genParamSpec,
-+    //         SecureRandom random)
-+    //         throws InvalidAlgorithmParameterException
-+    //     {
-+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
-+    //     }
-+    //
-+    //     protected AlgorithmParameters engineGenerateParameters()
-+    //     {
-+    //         byte[]  iv = new byte[16];
-+    //
-+    //         if (random == null)
-+    //         {
-+    //             random = new SecureRandom();
-+    //         }
-+    //
-+    //         random.nextBytes(iv);
-+    //
-+    //         AlgorithmParameters params;
-+    //
-+    //         try
-+    //         {
-+    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
-+    //             params.init(new IvParameterSpec(iv));
-+    //         }
-+    //         catch (Exception e)
-+    //         {
-+    //             throw new RuntimeException(e.getMessage());
-+    //         }
-+    //
-+    //         return params;
-+    //     }
-+    // }
-+    // END android-removed
- 
-     public static class AlgParams
-         extends JDKAlgorithmParameters.IVAlgorithmParameters
-@@ -205,58 +213,66 @@
-             put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-             put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
- 
--            put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
--            put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
--            put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
--            put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
--            put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
--            put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
--            put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-+            // BEGIN android-removed
-+            // put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
-+            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
-+            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
-+            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
-+            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-+            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-+            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-+            // END android-removed
- 
-             put("Cipher.AES", "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-             put("Alg.Alias.Cipher." + wrongAES128, "AES");
-             put("Alg.Alias.Cipher." + wrongAES192, "AES");
-             put("Alg.Alias.Cipher." + wrongAES256, "AES");
--            put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
--            put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
--            put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
--            put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
--            put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-+            // BEGIN android-removed
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-+            // END android-removed
-             put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$Wrap");
-             put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
-             put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
-             put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
--            put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
-+            // BEGIN android-removed
-+            // put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
-+            // END android-removed
- 
-             put("KeyGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
--            put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--            put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--            put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--            put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--
--            put("Mac.AESCMAC", "org.bouncycastle.jce.provider.symmetric.AES$AESCMAC");
-+            // BEGIN android-removed
-+            // put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+            // put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+            // put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+            // put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+            //
-+            // put("Mac.AESCMAC", "org.bouncycastle.jce.provider.symmetric.AES$AESCMAC");
-+            // END android-removed
-         }
-     }
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/ARC4.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/ARC4.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/ARC4.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/ARC4.java	2012-07-27 18:48:00.031478939 +0000
-@@ -27,7 +27,9 @@
-     {
-         public KeyGen()
-         {
--            super("RC4", 128, new CipherKeyGenerator());
-+            // BEGIN android-changed
-+            super("ARC4", 128, new CipherKeyGenerator());
-+            // END android-changed
-         }
-     }
- 
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/Blowfish.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/Blowfish.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/Blowfish.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/Blowfish.java	2012-07-27 18:48:00.031478939 +0000
-@@ -57,7 +57,9 @@
-         public Mappings()
-         {
-             put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$ECB");
--            put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.symmetric.Blowfish$CBC");
-+            // BEGIN android-removed
-+            // put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.symmetric.Blowfish$CBC");
-+            // END android-removed
-             put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$KeyGen");
-             put("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
-             put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$AlgParams");
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/DESede.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/DESede.java
---- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/DESede.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/DESede.java	2012-07-27 18:48:00.031478939 +0000
-@@ -14,11 +14,15 @@
- import org.bouncycastle.crypto.KeyGenerationParameters;
- import org.bouncycastle.crypto.engines.DESedeEngine;
- import org.bouncycastle.crypto.engines.DESedeWrapEngine;
--import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-+// END android-removed
- import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
- import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
--import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
--import org.bouncycastle.crypto.macs.CMac;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
-+// import org.bouncycastle.crypto.macs.CMac;
-+// END android-removed
- import org.bouncycastle.crypto.modes.CBCBlockCipher;
- import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
- import org.bouncycastle.jce.provider.JCEBlockCipher;
-@@ -51,17 +55,19 @@
-         }
-     }
- 
--    /**
--     * DESede   CFB8
--     */
--    public static class DESedeCFB8
--        extends JCEMac
--    {
--        public DESedeCFB8()
--        {
--            super(new CFBBlockCipherMac(new DESedeEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * DESede   CFB8
-+    //  */
-+    // public static class DESedeCFB8
-+    //     extends JCEMac
-+    // {
-+    //     public DESedeCFB8()
-+    //     {
-+    //         super(new CFBBlockCipherMac(new DESedeEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- 
-     /**
-      * DESede64
-@@ -96,14 +102,16 @@
-         }
-     }
- 
--    static public class CMAC
--        extends JCEMac
--    {
--        public CMAC()
--        {
--            super(new CMac(new DESedeEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class CMAC
-+    //     extends JCEMac
-+    // {
-+    //     public CMAC()
-+    //     {
-+    //         super(new CMac(new DESedeEngine()));
-+    //     }
-+    // }
-+    // END android-removed
- 
-     public static class Wrap
-         extends WrapCipherSpi
-@@ -114,14 +122,16 @@
-         }
-     }
- 
--    public static class RFC3211
--        extends WrapCipherSpi
--    {
--        public RFC3211()
--        {
--            super(new RFC3211WrapEngine(new DESedeEngine()), 8);
--        }
--    }
-+    // BEGIN android-removed
-+    // public static class RFC3211
-+    //     extends WrapCipherSpi
-+    // {
-+    //     public RFC3211()
-+    //     {
-+    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
-+    //     }
-+    // }
-+    // END android-removed
- 
-   /**
-      * DESede - the default for this is to generate a key in
-@@ -262,32 +272,42 @@
-         public Mappings()
-         {
-             put("Cipher.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$ECB");
--            put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
--            put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
-+            // BEGIN android-removed
-+            // put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
-+            // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
-+            // END android-removed
-             put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$Wrap");
--            put("Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "org.bouncycastle.jce.provider.symmetric.DESede$Wrap");
--            put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.DESede$RFC3211");
-+            // BEGIN android-changed
-+            put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
-+            // END android-changed
-+            // BEGIN android-removed
-+            // put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.DESede$RFC3211");
-+            // END android-removed
- 
-             put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
--            put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator3");
--            put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
-+            // BEGIN android-removed
-+            // put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator3");
-+            // put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
-+            // END android-removed
- 
-             put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyFactory");
- 
--            put("Mac.DESEDECMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CMAC");
--            put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CBCMAC");
--            put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
--
--            put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.symmetric.DESede$DESedeCFB8");
--            put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
--
--            put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64");
--            put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
--
--            put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64with7816d4");
--            put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
--            put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
--            put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+            // BEGIN android-removed
-+            // put("Mac.DESEDECMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CMAC");
-+            // put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CBCMAC");
-+            // put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
-+            //
-+            // put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.symmetric.DESede$DESedeCFB8");
-+            // put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
-+            //
-+            // put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64");
-+            // put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
-+            //
-+            // put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64with7816d4");
-+            // put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+            // put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+            // put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+            // END android-removed
-         }
-     }
- }
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/openssl/PEMUtilities.java bcprov-jdk16-146/org/bouncycastle/openssl/PEMUtilities.java
---- bcprov-jdk16-146.orig/org/bouncycastle/openssl/PEMUtilities.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/openssl/PEMUtilities.java	2012-07-27 18:48:00.031478939 +0000
-@@ -45,10 +45,12 @@
-         PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
-         PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
- 
--        KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), new Integer(192));
--        KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), new Integer(128));
--        KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), new Integer(192));
--        KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), new Integer(256));
-+        // BEGIN android-changed
-+        KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integer.valueOf(192));
-+        KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integer.valueOf(128));
-+        KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integer.valueOf(192));
-+        KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integer.valueOf(256));
-+        // END android-changed
-     }
- 
-     static int getKeySize(String algorithm)
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk16-146/org/bouncycastle/x509/X509Util.java
---- bcprov-jdk16-146.orig/org/bouncycastle/x509/X509Util.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/x509/X509Util.java	2012-07-27 18:48:00.011478563 +0000
-@@ -44,14 +44,18 @@
+ import org.bouncycastle.jce.X509Principal;
+@@ -44,14 +46,18 @@
      
      static
      {   
@@ -10848,7 +9388,7 @@
          algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
          algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
          algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
-@@ -59,45 +63,59 @@
+@@ -59,45 +65,59 @@
          algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
          algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
          algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -10924,7 +9464,7 @@
          noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
          noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
          noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
-@@ -105,25 +123,39 @@
+@@ -105,25 +125,39 @@
          //
          // RFC 4491
          //
@@ -10973,7 +9513,7 @@
          params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
      }
  
-@@ -166,7 +198,9 @@
+@@ -166,7 +200,9 @@
          }
          else
          {
@@ -10984,9 +9524,9 @@
          }
      }
      
-diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java bcprov-jdk16-146/org/bouncycastle/x509/extension/X509ExtensionUtil.java
---- bcprov-jdk16-146.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2011-02-23 20:08:56.000000000 +0000
-+++ bcprov-jdk16-146/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2012-07-27 18:48:00.011478563 +0000
+diff -Naur bcprov-jdk15on-147.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java bcprov-jdk15on-147/org/bouncycastle/x509/extension/X509ExtensionUtil.java
+--- bcprov-jdk15on-147.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2012-03-22 15:11:48.000000000 +0000
++++ bcprov-jdk15on-147/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2012-09-11 00:12:44.000000000 +0000
 @@ -62,7 +62,9 @@
              {
                  GeneralName genName = GeneralName.getInstance(it.nextElement());
@@ -10998,34 +9538,3 @@
                  switch (genName.getTagNo())
                  {
                  case GeneralName.ediPartyName:
-diff -Naur bcprov-jdk16-146.orig/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java.rej bcprov-jdk16-146/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java.rej
---- bcprov-jdk16-146.orig/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java.rej	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-146/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java.rej	2012-07-27 18:47:59.931477059 +0000
-@@ -0,0 +1,27 @@
-+--- src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java
-++++ src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java
-+@@ -144,8 +144,9 @@
-+         String pubkeyBlacklist = readBlacklist(path);
-+         if (!pubkeyBlacklist.equals("")) {
-+             for (String value : pubkeyBlacklist.split(",")) {
-++                value = value.trim();
-+                 if (isPubkeyHash(value)) {
-+-                    bl.add(Hex.decode(value));
-++                    bl.add(value.getBytes());
-+                 } else {
-+                     System.logW("Tried to blacklist invalid pubkey " + value);
-+                 }
-+@@ -161,7 +162,12 @@
-+         digest.update(encoded, 0, encoded.length);
-+         byte[] out = new byte[digest.getDigestSize()];
-+         digest.doFinal(out, 0);
-+-        return pubkeyBlacklist.contains(out);
-++        for (byte[] blacklisted : pubkeyBlacklist) {
-++            if (Arrays.equals(blacklisted, Hex.encode(out))) {
-++                return true;
-++            }
-++        }
-++        return false;
-+     }
-+ 
-+     public boolean isSerialNumberBlackListed(BigInteger serial) {
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
index f87064f..d7216a6 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
@@ -3,8 +3,8 @@
 import java.io.IOException;
 
 public interface ASN1ApplicationSpecificParser
-    extends DEREncodable, InMemoryRepresentable
+    extends ASN1Encodable, InMemoryRepresentable
 {
-    DEREncodable readObject()
+    ASN1Encodable readObject()
         throws IOException;
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
new file mode 100644
index 0000000..1360e8b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.asn1;
+
+public class ASN1Boolean
+    extends DERBoolean
+{
+    public ASN1Boolean(boolean value)
+    {
+        super(value);
+    }
+
+    ASN1Boolean(byte[] value)
+    {
+        super(value);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java b/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
index 77573a2..f5738bf 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
@@ -1,102 +1,6 @@
 package org.bouncycastle.asn1;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * Base class for objects which can be written directly to ASN.1 output streams.
- */
-public abstract class ASN1Encodable
-    implements DEREncodable
+public interface ASN1Encodable
 {
-    public static final String DER = "DER";
-    public static final String BER = "BER";
-
-    /**
-     * Return the default BER or DER encoding for this object.
-     *
-     * @return BER/DER byte encoded object.
-     * @throws IOException on encoding error.
-     */
-    public byte[] getEncoded() 
-        throws IOException
-    {
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
-        
-        aOut.writeObject(this);
-        
-        return bOut.toByteArray();
-    }
-
-    /**
-     * Return either the default for "BER" or a DER encoding if "DER" is specified.
-     *
-     * @param encoding name of encoding to use.
-     * @return byte encoded object.
-     * @throws IOException on encoding error.
-     */
-    public byte[] getEncoded(
-        String encoding) 
-        throws IOException
-    {
-        if (encoding.equals(DER))
-        {
-            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-            DEROutputStream         dOut = new DEROutputStream(bOut);
-            
-            dOut.writeObject(this);
-            
-            return bOut.toByteArray();
-        }
-        
-        return this.getEncoded();
-    }
-    
-    /**
-     * Return the DER encoding of the object, null if the DER encoding can not be made.
-     * 
-     * @return a DER byte array, null otherwise.
-     */
-    public byte[] getDEREncoded()
-    {
-        try
-        {
-            return this.getEncoded(DER);
-        }
-        catch (IOException e)
-        {
-            return null;
-        }
-    }
-    
-    public int hashCode()
-    {
-        return this.toASN1Object().hashCode();
-    }
-
-    public boolean equals(
-        Object  o)
-    {
-        if (this == o)
-        {
-            return true;
-        }
-        
-        if (!(o instanceof DEREncodable))
-        {
-            return false;
-        }
-
-        DEREncodable other = (DEREncodable)o;
-
-        return this.toASN1Object().equals(other.getDERObject());
-    }
-
-    public DERObject getDERObject()
-    {        
-        return this.toASN1Object();
-    }
-
-    public abstract DERObject toASN1Object();
+    ASN1Primitive toASN1Primitive();
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
index 3f736e4..2aa68b3 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
@@ -2,27 +2,22 @@
 
 import java.util.Vector;
 
-/**
- * the parent class for this will eventually disappear. Use this one!
- */
 public class ASN1EncodableVector
-    extends DEREncodableVector
 {
     Vector v = new Vector();
 
     public ASN1EncodableVector()
     {
-
     }
 
-    public void add(DEREncodable obj)
+    public void add(ASN1Encodable obj)
     {
         v.addElement(obj);
     }
 
-    public DEREncodable get(int i)
+    public ASN1Encodable get(int i)
     {
-        return (DEREncodable)v.elementAt(i);
+        return (ASN1Encodable)v.elementAt(i);
     }
 
     public int size()
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java b/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java
new file mode 100644
index 0000000..821d3b9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.asn1;
+
+public interface ASN1Encoding
+{
+    static final String DER = "DER";
+    static final String DL = "DL";
+    static final String BER = "BER";
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
index fb27edd..4471433 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
@@ -16,29 +16,17 @@
  */
 public class ASN1InputStream
     extends FilterInputStream
-    implements DERTags
+    implements BERTags
 {
     private final int limit;
     private final boolean lazyEvaluate;
 
-    static int findLimit(InputStream in)
-    {
-        if (in instanceof LimitedInputStream)
-        {
-            return ((LimitedInputStream)in).getRemaining();
-        }
-        else if (in instanceof ByteArrayInputStream)
-        {
-            return ((ByteArrayInputStream)in).available();
-        }
-
-        return Integer.MAX_VALUE;
-    }
+    private final byte[][] tmpBuffers;
 
     public ASN1InputStream(
         InputStream is)
     {
-        this(is, findLimit(is));
+        this(is, StreamUtil.findLimit(is));
     }
 
     /**
@@ -85,6 +73,20 @@
      * objects such as sequences will be parsed lazily.
      *
      * @param input stream containing ASN.1 encoded data.
+     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+     */
+    public ASN1InputStream(
+        InputStream input,
+        boolean     lazyEvaluate)
+    {
+        this(input, StreamUtil.findLimit(input), lazyEvaluate);
+    }
+
+    /**
+     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+     * objects such as sequences will be parsed lazily.
+     *
+     * @param input stream containing ASN.1 encoded data.
      * @param limit maximum size of a DER encoded object.
      * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
      */
@@ -96,6 +98,12 @@
         super(input);
         this.limit = limit;
         this.lazyEvaluate = lazyEvaluate;
+        this.tmpBuffers = new byte[11][];
+    }
+
+    int getLimit()
+    {
+        return limit;
     }
 
     protected int readLength()
@@ -117,7 +125,7 @@
     /**
      * build an object given its tag and the number of bytes to construct it from.
      */
-    protected DERObject buildObject(
+    protected ASN1Primitive buildObject(
         int       tag,
         int       tagNo,
         int       length)
@@ -146,33 +154,41 @@
                     //
                     // yes, people actually do this...
                     //
-                    return new BERConstructedOctetString(buildDEREncodableVector(defIn).v);
+                    ASN1EncodableVector v = buildDEREncodableVector(defIn);
+                    ASN1OctetString[] strings = new ASN1OctetString[v.size()];
+
+                    for (int i = 0; i != strings.length; i++)
+                    {
+                        strings[i] = (ASN1OctetString)v.get(i);
+                    }
+
+                    return new BEROctetString(strings);
                 case SEQUENCE:
                     if (lazyEvaluate)
                     {
-                        return new LazyDERSequence(defIn.toByteArray());
+                        return new LazyEncodedSequence(defIn.toByteArray());
                     }
                     else
                     {
                         return DERFactory.createSequence(buildDEREncodableVector(defIn));   
                     }
                 case SET:
-                    return DERFactory.createSet(buildDEREncodableVector(defIn), false);
+                    return DERFactory.createSet(buildDEREncodableVector(defIn));
                 case EXTERNAL:
                     return new DERExternal(buildDEREncodableVector(defIn));                
                 default:
-                    return new DERUnknownTag(true, tagNo, defIn.toByteArray());
+                    throw new IOException("unknown tag " + tagNo + " encountered");
             }
         }
 
-        return createPrimitiveDERObject(tagNo, defIn.toByteArray());
+        return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
     }
 
     ASN1EncodableVector buildEncodableVector()
         throws IOException
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
-        DERObject o;
+        ASN1Primitive o;
 
         while ((o = readObject()) != null)
         {
@@ -188,7 +204,7 @@
         return new ASN1InputStream(dIn).buildEncodableVector();
     }
 
-    public DERObject readObject()
+    public ASN1Primitive readObject()
         throws IOException
     {
         int tag = read();
@@ -352,52 +368,99 @@
         return length;
     }
 
-    static DERObject createPrimitiveDERObject(
+    private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
+        throws IOException
+    {
+        int len = defIn.getRemaining();
+        if (defIn.getRemaining() < tmpBuffers.length)
+        {
+            byte[] buf = tmpBuffers[len];
+
+            if (buf == null)
+            {
+                buf = tmpBuffers[len] = new byte[len];
+            }
+
+            Streams.readFully(defIn, buf);
+
+            return buf;
+        }
+        else
+        {
+            return defIn.toByteArray();
+        }
+    }
+
+    private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)
+        throws IOException
+    {
+        int len = defIn.getRemaining() / 2;
+        char[] buf = new char[len];
+        int totalRead = 0;
+        while (totalRead < len)
+        {
+            int ch1 = defIn.read();
+            if (ch1 < 0)
+            {
+                break;
+            }
+            int ch2 = defIn.read();
+            if (ch2 < 0)
+            {
+                break;
+            }
+            buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));
+        }
+
+        return buf;
+    }
+
+    static ASN1Primitive createPrimitiveDERObject(
         int     tagNo,
-        byte[]  bytes)
+        DefiniteLengthInputStream defIn,
+        byte[][] tmpBuffers)
+        throws IOException
     {
         switch (tagNo)
         {
             case BIT_STRING:
-                return DERBitString.fromOctetString(bytes);
+                return DERBitString.fromInputStream(defIn.getRemaining(), defIn);
             case BMP_STRING:
-                return new DERBMPString(bytes);
+                return new DERBMPString(getBMPCharBuffer(defIn));
             case BOOLEAN:
-                // BEGIN android-changed
-                return DERBoolean.getInstance(bytes);
-                // END android-changed
+                return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));
             case ENUMERATED:
-                return new ASN1Enumerated(bytes);
+                return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));
             case GENERALIZED_TIME:
-                return new ASN1GeneralizedTime(bytes);
+                return new ASN1GeneralizedTime(defIn.toByteArray());
             case GENERAL_STRING:
-                return new DERGeneralString(bytes);
+                return new DERGeneralString(defIn.toByteArray());
             case IA5_STRING:
-                return new DERIA5String(bytes);
+                return new DERIA5String(defIn.toByteArray());
             case INTEGER:
-                return new ASN1Integer(bytes);
+                return new ASN1Integer(defIn.toByteArray());
             case NULL:
                 return DERNull.INSTANCE;   // actual content is ignored (enforce 0 length?)
             case NUMERIC_STRING:
-                return new DERNumericString(bytes);
+                return new DERNumericString(defIn.toByteArray());
             case OBJECT_IDENTIFIER:
-                return new ASN1ObjectIdentifier(bytes);
+                return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));
             case OCTET_STRING:
-                return new DEROctetString(bytes);
+                return new DEROctetString(defIn.toByteArray());
             case PRINTABLE_STRING:
-                return new DERPrintableString(bytes);
+                return new DERPrintableString(defIn.toByteArray());
             case T61_STRING:
-                return new DERT61String(bytes);
+                return new DERT61String(defIn.toByteArray());
             case UNIVERSAL_STRING:
-                return new DERUniversalString(bytes);
+                return new DERUniversalString(defIn.toByteArray());
             case UTC_TIME:
-                return new ASN1UTCTime(bytes);
+                return new ASN1UTCTime(defIn.toByteArray());
             case UTF8_STRING:
-                return new DERUTF8String(bytes);
+                return new DERUTF8String(defIn.toByteArray());
             case VISIBLE_STRING:
-                return new DERVisibleString(bytes);
+                return new DERVisibleString(defIn.toByteArray());
             default:
-                return new DERUnknownTag(false, tagNo, bytes);
+                throw new IOException("unknown tag " + tagNo + " encountered");
         }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/src/main/java/org/bouncycastle/asn1/ASN1Null.java
index 539e7db..5b52da8 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Null.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Null.java
@@ -6,7 +6,7 @@
  * A NULL object.
  */
 public abstract class ASN1Null
-    extends ASN1Object
+    extends ASN1Primitive
 {
     // BEGIN android-changed
     /*package*/ ASN1Null()
@@ -14,13 +14,39 @@
     }
     // END android-changed
 
+    public static ASN1Null getInstance(Object o)
+    {
+        if (o instanceof ASN1Null)
+        {
+            return (ASN1Null)o;
+        }
+
+        if (o != null)
+        {
+            try
+            {
+                return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct NULL from byte[]: " + e.getMessage());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IllegalArgumentException("unknown object in getInstance(): " + o.getClass().getName());
+            }
+        }
+
+        return null;
+    }
+
     public int hashCode()
     {
         return -1;
     }
 
     boolean asn1Equals(
-        DERObject o)
+        ASN1Primitive o)
     {
         if (!(o instanceof ASN1Null))
         {
@@ -30,7 +56,7 @@
         return true;
     }
 
-    abstract void encode(DEROutputStream out)
+    abstract void encode(ASN1OutputStream out)
         throws IOException;
 
     public String toString()
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Object.java b/src/main/java/org/bouncycastle/asn1/ASN1Object.java
index 7e9860a..956fb7d 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Object.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Object.java
@@ -1,45 +1,97 @@
 package org.bouncycastle.asn1;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
-public abstract  class ASN1Object
-    extends DERObject
+public abstract class ASN1Object
+    implements ASN1Encodable
 {
     /**
-     * Create a base ASN.1 object from a byte stream.
+     * Return the default BER or DER encoding for this object.
      *
-     * @param data the byte stream to parse.
-     * @return the base ASN.1 object represented by the byte stream.
-     * @exception IOException if there is a problem parsing the data.
+     * @return BER/DER byte encoded object.
+     * @throws java.io.IOException on encoding error.
      */
-    public static ASN1Object fromByteArray(byte[] data)
+    public byte[] getEncoded()
         throws IOException
     {
-        ASN1InputStream aIn = new ASN1InputStream(data);
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
 
-        try
-        {
-            return (ASN1Object)aIn.readObject();
-        }
-        catch (ClassCastException e)
-        {
-            throw new IOException("cannot recognise object in stream");    
-        }
+        aOut.writeObject(this);
+
+        return bOut.toByteArray();
     }
 
-    public final boolean equals(Object o)
+    /**
+     * Return either the default for "BER" or a DER encoding if "DER" is specified.
+     *
+     * @param encoding name of encoding to use.
+     * @return byte encoded object.
+     * @throws IOException on encoding error.
+     */
+    public byte[] getEncoded(
+        String encoding)
+        throws IOException
+    {
+        if (encoding.equals(ASN1Encoding.DER))
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(this);
+
+            return bOut.toByteArray();
+        }
+        else if (encoding.equals(ASN1Encoding.DL))
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DLOutputStream          dOut = new DLOutputStream(bOut);
+
+            dOut.writeObject(this);
+
+            return bOut.toByteArray();
+        }
+
+        return this.getEncoded();
+    }
+
+    public int hashCode()
+    {
+        return this.toASN1Primitive().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
     {
         if (this == o)
         {
             return true;
         }
-        
-        return (o instanceof DEREncodable) && asn1Equals(((DEREncodable)o).getDERObject());
+
+        if (!(o instanceof ASN1Encodable))
+        {
+            return false;
+        }
+
+        ASN1Encodable other = (ASN1Encodable)o;
+
+        return this.toASN1Primitive().equals(other.toASN1Primitive());
     }
 
-    public abstract int hashCode();
+    /**
+     * @deprecated use toASN1Primitive()
+     * @return the underlying primitive type.
+     */
+    public ASN1Primitive toASN1Object()
+    {
+        return this.toASN1Primitive();
+    }
 
-    abstract void encode(DEROutputStream out) throws IOException;
+    protected static boolean hasEncodedTagValue(Object obj, int tagValue)
+    {
+        return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue;
+    }
 
-    abstract boolean asn1Equals(DERObject o);
+    public abstract ASN1Primitive toASN1Primitive();
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
index 83b7c86..eb29838 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -17,10 +17,21 @@
      * Return an OID that creates a branch under the current one.
      *
      * @param branchID node numbers for the new branch.
-     * @return
+     * @return the OID for the new created branch.
      */
     public ASN1ObjectIdentifier branch(String branchID)
     {
         return new ASN1ObjectIdentifier(getId() + "." + branchID);
     }
+
+    /**
+     * Return  true if this oid is an extension of the passed in branch, stem.
+     * @param stem the arc or branch that is a possible parent.
+     * @return  true if the branch is on the passed in stem, false otherwise.
+     */
+    public boolean on(ASN1ObjectIdentifier stem)
+    {
+        String id = getId(), stemId = stem.getId();
+        return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
index 7d334d7..703b858 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
@@ -8,7 +8,7 @@
 import org.bouncycastle.util.encoders.Hex;
 
 public abstract class ASN1OctetString
-    extends ASN1Object
+    extends ASN1Primitive
     implements ASN1OctetStringParser
 {
     byte[]  string;
@@ -26,7 +26,7 @@
         ASN1TaggedObject    obj,
         boolean             explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof ASN1OctetString)
         {
@@ -34,7 +34,7 @@
         }
         else
         {
-            return BERConstructedOctetString.fromSequence(ASN1Sequence.getInstance(o)); 
+            return BEROctetString.fromSequence(ASN1Sequence.getInstance(o));
         }
     }
     
@@ -51,11 +51,25 @@
         {
             return (ASN1OctetString)obj;
         }
-
-        // TODO: this needs to be deleted in V2
-        if (obj instanceof ASN1TaggedObject)
+        else if (obj instanceof byte[])
         {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
+            try
+            {
+                return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage());
+            }
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1OctetString)
+            {
+                return (ASN1OctetString)primitive;
+            }
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -74,19 +88,6 @@
         this.string = string;
     }
 
-    public ASN1OctetString(
-        DEREncodable obj)
-    {
-        try
-        {
-            this.string = obj.getDERObject().getEncoded(ASN1Encodable.DER);
-        }
-        catch (IOException e)
-        {
-            throw new IllegalArgumentException("Error processing object : " + e.toString());
-        }
-    }
-
     public InputStream getOctetStream()
     {
         return new ByteArrayInputStream(string);
@@ -108,7 +109,7 @@
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof ASN1OctetString))
         {
@@ -120,12 +121,22 @@
         return Arrays.areEqual(string, other.string);
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
     {
-        return this.getDERObject();
+        return this.toASN1Primitive();
     }
 
-    abstract void encode(DEROutputStream out)
+    ASN1Primitive toDERObject()
+    {
+        return new DEROctetString(string);
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        return new DEROctetString(string);
+    }
+
+    abstract void encode(ASN1OutputStream out)
         throws IOException;
 
     public String toString()
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java b/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
index 21a3941..0042317 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
@@ -3,7 +3,7 @@
 import java.io.InputStream;
 
 public interface ASN1OctetStringParser
-    extends DEREncodable, InMemoryRepresentable
+    extends ASN1Encodable, InMemoryRepresentable
 {
     public InputStream getOctetStream();
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java b/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
index 5897d09..9a46a78 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
@@ -3,34 +3,192 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+/**
+ * Stream that produces output based on the default encoding for the passed in objects.
+ */
 public class ASN1OutputStream
-    extends DEROutputStream
 {
+    private OutputStream os;
+
     public ASN1OutputStream(
         OutputStream    os)
     {
-        super(os);
+        this.os = os;
     }
 
-    public void writeObject(
-        Object    obj)
+    void writeLength(
+        int length)
         throws IOException
     {
-        if (obj == null)
+        if (length > 127)
         {
-            writeNull();
-        }
-        else if (obj instanceof DERObject)
-        {
-            ((DERObject)obj).encode(this);
-        }
-        else if (obj instanceof DEREncodable)
-        {
-            ((DEREncodable)obj).getDERObject().encode(this);
+            int size = 1;
+            int val = length;
+
+            while ((val >>>= 8) != 0)
+            {
+                size++;
+            }
+
+            write((byte)(size | 0x80));
+
+            for (int i = (size - 1) * 8; i >= 0; i -= 8)
+            {
+                write((byte)(length >> i));
+            }
         }
         else
         {
-            throw new IOException("object not ASN1Encodable");
+            write((byte)length);
+        }
+    }
+
+    void write(int b)
+        throws IOException
+    {
+        os.write(b);
+    }
+
+    void write(byte[] bytes)
+        throws IOException
+    {
+        os.write(bytes);
+    }
+
+    void write(byte[] bytes, int off, int len)
+        throws IOException
+    {
+        os.write(bytes, off, len);
+    }
+
+    void writeEncoded(
+        int     tag,
+        byte[]  bytes)
+        throws IOException
+    {
+        write(tag);
+        writeLength(bytes.length);
+        write(bytes);
+    }
+
+    void writeTag(int flags, int tagNo)
+        throws IOException
+    {
+        if (tagNo < 31)
+        {
+            write(flags | tagNo);
+        }
+        else
+        {
+            write(flags | 0x1f);
+            if (tagNo < 128)
+            {
+                write(tagNo);
+            }
+            else
+            {
+                byte[] stack = new byte[5];
+                int pos = stack.length;
+
+                stack[--pos] = (byte)(tagNo & 0x7F);
+
+                do
+                {
+                    tagNo >>= 7;
+                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+                }
+                while (tagNo > 127);
+
+                write(stack, pos, stack.length - pos);
+            }
+        }
+    }
+
+    void writeEncoded(int flags, int tagNo, byte[] bytes)
+        throws IOException
+    {
+        writeTag(flags, tagNo);
+        writeLength(bytes.length);
+        write(bytes);
+    }
+
+    protected void writeNull()
+        throws IOException
+    {
+        os.write(BERTags.NULL);
+        os.write(0x00);
+    }
+
+    public void writeObject(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.toASN1Primitive().encode(this);
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+
+    void writeImplicitObject(ASN1Primitive obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.encode(new ImplicitOutputStream(os));
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+
+    public void close()
+        throws IOException
+    {
+        os.close();
+    }
+
+    public void flush()
+        throws IOException
+    {
+        os.flush();
+    }
+
+    ASN1OutputStream getDERSubStream()
+    {
+        return new DEROutputStream(os);
+    }
+
+    ASN1OutputStream getDLSubStream()
+    {
+        return new DLOutputStream(os);
+    }
+
+    private class ImplicitOutputStream
+        extends ASN1OutputStream
+    {
+        private boolean first = true;
+
+        public ImplicitOutputStream(OutputStream os)
+        {
+            super(os);
+        }
+
+        public void write(int b)
+            throws IOException
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                super.write(b);
+            }
         }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java b/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
index 2abdb18..995b5e9 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
@@ -5,12 +5,12 @@
 {
     private Throwable cause;
 
-    ASN1ParsingException(String message)
+    public ASN1ParsingException(String message)
     {
         super(message);
     }
 
-    ASN1ParsingException(String message, Throwable cause)
+    public ASN1ParsingException(String message, Throwable cause)
     {
         super(message);
         this.cause = cause;
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java b/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java
new file mode 100644
index 0000000..e6fe137
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public abstract class ASN1Primitive
+    extends ASN1Object
+{
+    ASN1Primitive()
+    {
+
+    }
+
+    /**
+     * Create a base ASN.1 object from a byte stream.
+     *
+     * @param data the byte stream to parse.
+     * @return the base ASN.1 object represented by the byte stream.
+     * @exception IOException if there is a problem parsing the data.
+     */
+    public static ASN1Primitive fromByteArray(byte[] data)
+        throws IOException
+    {
+        ASN1InputStream aIn = new ASN1InputStream(data);
+
+        try
+        {
+            return aIn.readObject();
+        }
+        catch (ClassCastException e)
+        {
+            throw new IOException("cannot recognise object in stream");
+        }
+    }
+
+    public final boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+
+        return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive());
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return this;
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        return this;
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        return this;
+    }
+
+    public abstract int hashCode();
+
+    abstract boolean isConstructed();
+
+    abstract int encodedLength() throws IOException;
+
+    abstract void encode(ASN1OutputStream out) throws IOException;
+
+    abstract boolean asn1Equals(ASN1Primitive o);
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
index b4a8072..0507a2b 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
@@ -5,9 +5,9 @@
 import java.util.Vector;
 
 public abstract class ASN1Sequence
-    extends ASN1Object
+    extends ASN1Primitive
 {
-    private Vector seq = new Vector();
+    protected Vector seq = new Vector();
 
     /**
      * return an ASN1Sequence from the given object.
@@ -22,17 +22,30 @@
         {
             return (ASN1Sequence)obj;
         }
+        else if (obj instanceof ASN1SequenceParser)
+        {
+            return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
+        }
         else if (obj instanceof byte[])
         {
             try
             {
-                return ASN1Sequence.getInstance(ASN1Object.fromByteArray((byte[])obj));
+                return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
             }
             catch (IOException e)
             {
                 throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
             }
         }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1Sequence)
+            {
+                return (ASN1Sequence)primitive;
+            }
+        }
 
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
@@ -64,7 +77,7 @@
                 throw new IllegalArgumentException("object implicit - explicit expected.");
             }
 
-            return (ASN1Sequence)obj.getObject();
+            return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());
         }
         else
         {
@@ -81,7 +94,7 @@
                 }
                 else
                 {
-                    return new DERSequence(obj.getObject());
+                    return new DLSequence(obj.getObject());
                 }
             }
             else
@@ -96,6 +109,58 @@
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
 
+    /**
+     * create an empty sequence
+     */
+    protected ASN1Sequence()
+    {
+    }
+
+    /**
+     * create a sequence containing one object
+     */
+    protected ASN1Sequence(
+        ASN1Encodable obj)
+    {
+        seq.addElement(obj);
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    protected ASN1Sequence(
+        ASN1EncodableVector v)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            seq.addElement(v.get(i));
+        }
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    protected ASN1Sequence(
+        ASN1Encodable[]   array)
+    {
+        for (int i = 0; i != array.length; i++)
+        {
+            seq.addElement(array[i]);
+        }
+    }
+
+    public ASN1Encodable[] toArray()
+    {
+        ASN1Encodable[] values = new ASN1Encodable[this.size()];
+
+        for (int i = 0; i != this.size(); i++)
+        {
+            values[i] = this.getObjectAt(i);
+        }
+
+        return values;
+    }
+
     public Enumeration getObjects()
     {
         return seq.elements();
@@ -111,14 +176,14 @@
 
             private int index;
 
-            public DEREncodable readObject() throws IOException
+            public ASN1Encodable readObject() throws IOException
             {
                 if (index == max)
                 {
                     return null;
                 }
                 
-                DEREncodable obj = getObjectAt(index++);
+                ASN1Encodable obj = getObjectAt(index++);
                 if (obj instanceof ASN1Sequence)
                 {
                     return ((ASN1Sequence)obj).parser();
@@ -131,12 +196,12 @@
                 return obj;
             }
 
-            public DERObject getLoadedObject()
+            public ASN1Primitive getLoadedObject()
             {
                 return outer;
             }
             
-            public DERObject getDERObject()
+            public ASN1Primitive toASN1Primitive()
             {
                 return outer;
             }
@@ -149,10 +214,10 @@
      * @param index the sequence number (starting at zero) of the object
      * @return the object at the sequence position indicated by index.
      */
-    public DEREncodable getObjectAt(
+    public ASN1Encodable getObjectAt(
         int index)
     {
-        return (DEREncodable)seq.elementAt(index);
+        return (ASN1Encodable)seq.elementAt(index);
     }
 
     /**
@@ -182,7 +247,7 @@
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof ASN1Sequence))
         {
@@ -201,11 +266,11 @@
 
         while (s1.hasMoreElements())
         {
-            DEREncodable  obj1 = getNext(s1);
-            DEREncodable  obj2 = getNext(s2);
+            ASN1Encodable obj1 = getNext(s1);
+            ASN1Encodable obj2 = getNext(s2);
 
-            DERObject  o1 = obj1.getDERObject();
-            DERObject  o2 = obj2.getDERObject();
+            ASN1Primitive o1 = obj1.toASN1Primitive();
+            ASN1Primitive o2 = obj2.toASN1Primitive();
 
             if (o1 == o2 || o1.equals(o2))
             {
@@ -218,30 +283,41 @@
         return true;
     }
 
-    private DEREncodable getNext(Enumeration e)
+    private ASN1Encodable getNext(Enumeration e)
     {
-        DEREncodable encObj = (DEREncodable)e.nextElement();
-
-        // unfortunately null was allowed as a substitute for DER null
-        if (encObj == null)
-        {
-            return DERNull.INSTANCE;
-        }
+        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
 
         return encObj;
     }
 
-    protected void addObject(
-        DEREncodable obj)
+    ASN1Primitive toDERObject()
     {
-        seq.addElement(obj);
+        ASN1Sequence derSeq = new DERSequence();
+
+        derSeq.seq = this.seq;
+
+        return derSeq;
     }
 
-    abstract void encode(DEROutputStream out)
+    ASN1Primitive toDLObject()
+    {
+        ASN1Sequence dlSeq = new DLSequence();
+
+        dlSeq.seq = this.seq;
+
+        return dlSeq;
+    }
+
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    abstract void encode(ASN1OutputStream out)
         throws IOException;
 
     public String toString() 
     {
-      return seq.toString();
+        return seq.toString();
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java b/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
index 49dde79..441f150 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
@@ -3,8 +3,8 @@
 import java.io.IOException;
 
 public interface ASN1SequenceParser
-    extends DEREncodable, InMemoryRepresentable
+    extends ASN1Encodable, InMemoryRepresentable
 {
-    DEREncodable readObject()
+    ASN1Encodable readObject()
         throws IOException;
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/src/main/java/org/bouncycastle/asn1/ASN1Set.java
index c395b8b..8f785b8 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Set.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Set.java
@@ -6,9 +6,10 @@
 import java.util.Vector;
 
 abstract public class ASN1Set
-    extends ASN1Object
+    extends ASN1Primitive
 {
-    protected Vector set = new Vector();
+    private Vector set = new Vector();
+    private boolean isSorted = false;
 
     /**
      * return an ASN1Set from the given object.
@@ -23,6 +24,30 @@
         {
             return (ASN1Set)obj;
         }
+        else if (obj instanceof ASN1SetParser)
+        {
+            return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive());
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage());
+            }
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1Set)
+            {
+                return (ASN1Set)primitive;
+            }
+        }
 
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
@@ -61,13 +86,18 @@
             //
             // constructed object which appears to be explicitly tagged
             // and it's really implicit means we have to add the
-            // surrounding sequence.
+            // surrounding set.
             //
             if (obj.isExplicit())
             {
-                ASN1Set    set = new DERSet(obj.getObject());
-
-                return set;
+                if (obj instanceof BERTaggedObject)
+                {
+                    return new BERSet(obj.getObject());
+                }
+                else
+                {
+                    return new DLSet(obj.getObject());
+                }
             }
             else
             {
@@ -80,19 +110,22 @@
                 // in this case the parser returns a sequence, convert it
                 // into a set.
                 //
-                ASN1EncodableVector  v = new ASN1EncodableVector();
+
+
+                ASN1EncodableVector v = new ASN1EncodableVector();
 
                 if (obj.getObject() instanceof ASN1Sequence)
                 {
                     ASN1Sequence s = (ASN1Sequence)obj.getObject();
-                    Enumeration e = s.getObjects();
 
-                    while (e.hasMoreElements())
+                    if (obj instanceof BERTaggedObject)
                     {
-                        v.add((DEREncodable)e.nextElement());
+                        return new BERSet(s.toArray());
                     }
-
-                    return new DERSet(v, false);
+                    else
+                    {
+                        return new DLSet(s.toArray());
+                    }
                 }
             }
         }
@@ -100,10 +133,55 @@
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
 
-    public ASN1Set()
+    protected ASN1Set()
     {
     }
 
+    /**
+     * create a sequence containing one object
+     */
+    protected ASN1Set(
+        ASN1Encodable obj)
+    {
+        set.addElement(obj);
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    protected ASN1Set(
+        ASN1EncodableVector v,
+        boolean                  doSort)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            set.addElement(v.get(i));
+        }
+
+        if (doSort)
+        {
+            this.sort();
+        }
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    protected ASN1Set(
+        ASN1Encodable[]   array,
+        boolean doSort)
+    {
+        for (int i = 0; i != array.length; i++)
+        {
+            set.addElement(array[i]);
+        }
+
+        if (doSort)
+        {
+            this.sort();
+        }
+    }
+
     public Enumeration getObjects()
     {
         return set.elements();
@@ -115,10 +193,10 @@
      * @param index the set number (starting at zero) of the object
      * @return the object at the set position indicated by index.
      */
-    public DEREncodable getObjectAt(
+    public ASN1Encodable getObjectAt(
         int index)
     {
-        return (DEREncodable)set.elementAt(index);
+        return (ASN1Encodable)set.elementAt(index);
     }
 
     /**
@@ -137,7 +215,7 @@
 
         for (int i = 0; i != this.size(); i++)
         {
-            values[i] = (ASN1Encodable)this.getObjectAt(i);
+            values[i] = this.getObjectAt(i);
         }
 
         return values;
@@ -153,14 +231,14 @@
 
             private int index;
 
-            public DEREncodable readObject() throws IOException
+            public ASN1Encodable readObject() throws IOException
             {
                 if (index == max)
                 {
                     return null;
                 }
 
-                DEREncodable obj = getObjectAt(index++);
+                ASN1Encodable obj = getObjectAt(index++);
                 if (obj instanceof ASN1Sequence)
                 {
                     return ((ASN1Sequence)obj).parser();
@@ -173,12 +251,12 @@
                 return obj;
             }
 
-            public DERObject getLoadedObject()
+            public ASN1Primitive getLoadedObject()
             {
                 return outer;
             }
 
-            public DERObject getDERObject()
+            public ASN1Primitive toASN1Primitive()
             {
                 return outer;
             }
@@ -201,8 +279,46 @@
         return hashCode;
     }
 
+    ASN1Primitive toDERObject()
+    {
+        if (isSorted)
+        {
+            ASN1Set derSet = new DERSet();
+
+            derSet.set = this.set;
+
+            return derSet;
+        }
+        else
+        {
+            Vector v = new Vector();
+
+            for (int i = 0; i != set.size(); i++)
+            {
+                v.addElement(set.elementAt(i));
+            }
+
+            ASN1Set derSet = new DERSet();
+
+            derSet.set = v;
+
+            derSet.sort();
+
+            return derSet;
+        }
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        ASN1Set derSet = new DLSet();
+
+        derSet.set = this.set;
+
+        return derSet;
+    }
+
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof ASN1Set))
         {
@@ -221,11 +337,11 @@
 
         while (s1.hasMoreElements())
         {
-            DEREncodable  obj1 = getNext(s1);
-            DEREncodable  obj2 = getNext(s2);
+            ASN1Encodable obj1 = getNext(s1);
+            ASN1Encodable obj2 = getNext(s2);
 
-            DERObject  o1 = obj1.getDERObject();
-            DERObject  o2 = obj2.getDERObject();
+            ASN1Primitive o1 = obj1.toASN1Primitive();
+            ASN1Primitive o2 = obj2.toASN1Primitive();
 
             if (o1 == o2 || o1.equals(o2))
             {
@@ -238,9 +354,9 @@
         return true;
     }
 
-    private DEREncodable getNext(Enumeration e)
+    private ASN1Encodable getNext(Enumeration e)
     {
-        DEREncodable encObj = (DEREncodable)e.nextElement();
+        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
 
         // unfortunately null was allowed as a substitute for DER null
         if (encObj == null)
@@ -270,7 +386,7 @@
     }
 
     private byte[] getEncoded(
-        DEREncodable obj)
+        ASN1Encodable obj)
     {
         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
         ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
@@ -289,57 +405,60 @@
 
     protected void sort()
     {
-        if (set.size() > 1)
+        if (!isSorted)
         {
-            boolean    swapped = true;
-            int        lastSwap = set.size() - 1;
-
-            while (swapped)
+            isSorted = true;
+            if (set.size() > 1)
             {
-                int    index = 0;
-                int    swapIndex = 0;
-                byte[] a = getEncoded((DEREncodable)set.elementAt(0));
-                
-                swapped = false;
+                boolean    swapped = true;
+                int        lastSwap = set.size() - 1;
 
-                while (index != lastSwap)
+                while (swapped)
                 {
-                    byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
+                    int    index = 0;
+                    int    swapIndex = 0;
+                    byte[] a = getEncoded((ASN1Encodable)set.elementAt(0));
 
-                    if (lessThanOrEqual(a, b))
+                    swapped = false;
+
+                    while (index != lastSwap)
                     {
-                        a = b;
-                    }
-                    else
-                    {
-                        Object  o = set.elementAt(index);
+                        byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1));
 
-                        set.setElementAt(set.elementAt(index + 1), index);
-                        set.setElementAt(o, index + 1);
+                        if (lessThanOrEqual(a, b))
+                        {
+                            a = b;
+                        }
+                        else
+                        {
+                            Object  o = set.elementAt(index);
 
-                        swapped = true;
-                        swapIndex = index;
+                            set.setElementAt(set.elementAt(index + 1), index);
+                            set.setElementAt(o, index + 1);
+
+                            swapped = true;
+                            swapIndex = index;
+                        }
+
+                        index++;
                     }
 
-                    index++;
+                    lastSwap = swapIndex;
                 }
-
-                lastSwap = swapIndex;
             }
         }
     }
 
-    protected void addObject(
-        DEREncodable obj)
+    boolean isConstructed()
     {
-        set.addElement(obj);
+        return true;
     }
 
-    abstract void encode(DEROutputStream out)
+    abstract void encode(ASN1OutputStream out)
             throws IOException;
 
     public String toString() 
     {
-      return set.toString();
+        return set.toString();
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java b/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
index 9dc99b5..e025535 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
@@ -3,8 +3,8 @@
 import java.io.IOException;
 
 public interface ASN1SetParser
-    extends DEREncodable, InMemoryRepresentable
+    extends ASN1Encodable, InMemoryRepresentable
 {
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException;
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java b/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
index fbcb787..420fa34 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
@@ -8,11 +8,12 @@
 {
     private final InputStream _in;
     private final int         _limit;
+    private final byte[][] tmpBuffers;
 
     public ASN1StreamParser(
         InputStream in)
     {
-        this(in, ASN1InputStream.findLimit(in));
+        this(in, StreamUtil.findLimit(in));
     }
 
     public ASN1StreamParser(
@@ -21,6 +22,8 @@
     {
         this._in = in;
         this._limit = limit;
+
+        this.tmpBuffers = new byte[11][];
     }
 
     public ASN1StreamParser(
@@ -29,27 +32,27 @@
         this(new ByteArrayInputStream(encoding), encoding.length);
     }
 
-    DEREncodable readIndef(int tagValue) throws IOException
+    ASN1Encodable readIndef(int tagValue) throws IOException
     {
         // Note: INDEF => CONSTRUCTED
 
         // TODO There are other tags that may be constructed (e.g. BIT_STRING)
         switch (tagValue)
         {
-            case DERTags.EXTERNAL:
+            case BERTags.EXTERNAL:
                 return new DERExternalParser(this);
-            case DERTags.OCTET_STRING:
+            case BERTags.OCTET_STRING:
                 return new BEROctetStringParser(this);
-            case DERTags.SEQUENCE:
+            case BERTags.SEQUENCE:
                 return new BERSequenceParser(this);
-            case DERTags.SET:
+            case BERTags.SET:
                 return new BERSetParser(this);
             default:
                 throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
         }
     }
 
-    DEREncodable readImplicit(boolean constructed, int tag) throws IOException
+    ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException
     {
         if (_in instanceof IndefiniteLengthInputStream)
         {
@@ -65,11 +68,11 @@
         {
             switch (tag)
             {
-                case DERTags.SET:
+                case BERTags.SET:
                     return new DERSetParser(this);
-                case DERTags.SEQUENCE:
+                case BERTags.SEQUENCE:
                     return new DERSequenceParser(this);
-                case DERTags.OCTET_STRING:
+                case BERTags.OCTET_STRING:
                     return new BEROctetStringParser(this);
             }
         }
@@ -77,11 +80,11 @@
         {
             switch (tag)
             {
-                case DERTags.SET:
+                case BERTags.SET:
                     throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
-                case DERTags.SEQUENCE:
+                case BERTags.SEQUENCE:
                     throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
-                case DERTags.OCTET_STRING:
+                case BERTags.OCTET_STRING:
                     return new DEROctetStringParser((DefiniteLengthInputStream)_in);
             }
         }
@@ -90,7 +93,7 @@
         throw new RuntimeException("implicit tagging not implemented");
     }
 
-    DERObject readTaggedObject(boolean constructed, int tag) throws IOException
+    ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException
     {
         if (!constructed)
         {
@@ -113,7 +116,7 @@
             :   new DERTaggedObject(false, tag, DERFactory.createSequence(v));
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         int tag = _in.read();
@@ -132,7 +135,7 @@
         //
         int tagNo = ASN1InputStream.readTagNumber(_in, tag);
 
-        boolean isConstructed = (tag & DERTags.CONSTRUCTED) != 0;
+        boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;
 
         //
         // calculate length
@@ -149,12 +152,12 @@
             IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
             ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
 
-            if ((tag & DERTags.APPLICATION) != 0)
+            if ((tag & BERTags.APPLICATION) != 0)
             {
                 return new BERApplicationSpecificParser(tagNo, sp);
             }
 
-            if ((tag & DERTags.TAGGED) != 0)
+            if ((tag & BERTags.TAGGED) != 0)
             {
                 return new BERTaggedObjectParser(true, tagNo, sp);
             }
@@ -165,12 +168,12 @@
         {
             DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
 
-            if ((tag & DERTags.APPLICATION) != 0)
+            if ((tag & BERTags.APPLICATION) != 0)
             {
                 return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
             }
 
-            if ((tag & DERTags.TAGGED) != 0)
+            if ((tag & BERTags.TAGGED) != 0)
             {
                 return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
             }
@@ -180,33 +183,32 @@
                 // TODO There are other tags that may be constructed (e.g. BIT_STRING)
                 switch (tagNo)
                 {
-                    case DERTags.OCTET_STRING:
+                    case BERTags.OCTET_STRING:
                         //
                         // yes, people actually do this...
                         //
                         return new BEROctetStringParser(new ASN1StreamParser(defIn));
-                    case DERTags.SEQUENCE:
+                    case BERTags.SEQUENCE:
                         return new DERSequenceParser(new ASN1StreamParser(defIn));
-                    case DERTags.SET:
+                    case BERTags.SET:
                         return new DERSetParser(new ASN1StreamParser(defIn));
-                    case DERTags.EXTERNAL:
+                    case BERTags.EXTERNAL:
                         return new DERExternalParser(new ASN1StreamParser(defIn));
                     default:
-                        // TODO Add DERUnknownTagParser class?
-                        return new DERUnknownTag(true, tagNo, defIn.toByteArray());
+                        throw new IOException("unknown tag " + tagNo + " encountered");
                 }
             }
 
             // Some primitive encodings can be handled by parsers too...
             switch (tagNo)
             {
-                case DERTags.OCTET_STRING:
+                case BERTags.OCTET_STRING:
                     return new DEROctetStringParser(defIn);
             }
 
             try
             {
-                return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn.toByteArray());
+                return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
             }
             catch (IllegalArgumentException e)
             {
@@ -227,7 +229,7 @@
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        DEREncodable obj;
+        ASN1Encodable obj;
         while ((obj = readObject()) != null)
         {
             if (obj instanceof InMemoryRepresentable)
@@ -236,7 +238,7 @@
             }
             else
             {
-                v.add(obj.getDERObject());
+                v.add(obj.toASN1Primitive());
             }
         }
 
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
index 8ee7960..fb1e244 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
@@ -8,13 +8,13 @@
  * rules (as with sequences).
  */
 public abstract class ASN1TaggedObject
-    extends ASN1Object
+    extends ASN1Primitive
     implements ASN1TaggedObjectParser
 {
     int             tagNo;
     boolean         empty = false;
     boolean         explicit = true;
-    DEREncodable    obj = null;
+    ASN1Encodable obj = null;
 
     static public ASN1TaggedObject getInstance(
         ASN1TaggedObject    obj,
@@ -35,26 +35,22 @@
         {
                 return (ASN1TaggedObject)obj;
         }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage());
+            }
+        }
 
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
 
     /**
-     * Create a tagged object in the explicit style.
-     * 
-     * @param tagNo the tag number for this object.
-     * @param obj the tagged object.
-     */
-    public ASN1TaggedObject(
-        int             tagNo,
-        DEREncodable    obj)
-    {
-        this.explicit = true;
-        this.tagNo = tagNo;
-        this.obj = obj;
-    }
-
-    /**
      * Create a tagged object with the style given by the value of explicit.
      * <p>
      * If the object implements ASN1Choice the tag style will always be changed
@@ -67,7 +63,7 @@
     public ASN1TaggedObject(
         boolean         explicit,
         int             tagNo,
-        DEREncodable    obj)
+        ASN1Encodable   obj)
     {
         if (obj instanceof ASN1Choice)
         {
@@ -79,11 +75,26 @@
         }
         
         this.tagNo = tagNo;
-        this.obj = obj;
+
+        if (this.explicit)
+        {
+            this.obj = obj;
+        }
+        else
+        {
+            ASN1Primitive prim = obj.toASN1Primitive();
+
+            if (prim instanceof ASN1Set)
+            {
+                ASN1Set s = null;
+            }
+
+            this.obj = obj;
+        }
     }
     
     boolean asn1Equals(
-        DERObject o)
+        ASN1Primitive o)
     {
         if (!(o instanceof ASN1TaggedObject))
         {
@@ -106,7 +117,7 @@
         }
         else
         {
-            if (!(obj.getDERObject().equals(other.obj.getDERObject())))
+            if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive())))
             {
                 return false;
             }
@@ -163,11 +174,11 @@
      * trying to extract a tagged object you should be going via the
      * appropriate getInstance method.
      */
-    public DERObject getObject()
+    public ASN1Primitive getObject()
     {
         if (obj != null)
         {
-            return obj.getDERObject();
+            return obj.toASN1Primitive();
         }
 
         return null;
@@ -178,17 +189,17 @@
      * the type of the passed in tag. If the object doesn't have a parser
      * associated with it, the base object is returned.
      */
-    public DEREncodable getObjectParser(
+    public ASN1Encodable getObjectParser(
         int     tag,
         boolean isExplicit)
     {
         switch (tag)
         {
-        case DERTags.SET:
+        case BERTags.SET:
             return ASN1Set.getInstance(this, isExplicit).parser();
-        case DERTags.SEQUENCE:
+        case BERTags.SEQUENCE:
             return ASN1Sequence.getInstance(this, isExplicit).parser();
-        case DERTags.OCTET_STRING:
+        case BERTags.OCTET_STRING:
             return ASN1OctetString.getInstance(this, isExplicit).parser();
         }
 
@@ -200,12 +211,22 @@
         throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
     {
-        return this.getDERObject();
+        return this.toASN1Primitive();
     }
-    
-    abstract void encode(DEROutputStream  out)
+
+    ASN1Primitive toDERObject()
+    {
+        return new DERTaggedObject(explicit, tagNo, obj);
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        return new DLTaggedObject(explicit, tagNo, obj);
+    }
+
+    abstract void encode(ASN1OutputStream out)
         throws IOException;
 
     public String toString()
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
index 52f6087..a681dc9 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
@@ -3,10 +3,10 @@
 import java.io.IOException;
 
 public interface ASN1TaggedObjectParser
-    extends DEREncodable, InMemoryRepresentable
+    extends ASN1Encodable, InMemoryRepresentable
 {
     public int getTagNo();
     
-    public DEREncodable getObjectParser(int tag, boolean isExplicit)
+    public ASN1Encodable getObjectParser(int tag, boolean isExplicit)
         throws IOException;
 }
diff --git a/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
index 7b6aaaf..63bd9f3 100644
--- a/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
@@ -14,19 +14,19 @@
         this.parser = parser;
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         return parser.readObject();
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
          return new BERApplicationSpecific(tag, parser.readVector());
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java b/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
index cceb241..cad6e42 100644
--- a/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
+++ b/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
@@ -5,8 +5,11 @@
 import java.util.Enumeration;
 import java.util.Vector;
 
+/**
+ * @deprecated use BEROctetString
+ */
 public class BERConstructedOctetString
-    extends DEROctetString
+    extends BEROctetString
 {
     private static final int MAX_LENGTH = 1000;
 
@@ -59,15 +62,27 @@
     }
 
     public BERConstructedOctetString(
-        DERObject  obj)
+        ASN1Primitive  obj)
     {
-        super(obj);
+        super(toByteArray(obj));
+    }
+
+    private static byte[] toByteArray(ASN1Primitive obj)
+    {
+        try
+        {
+            return obj.getEncoded();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("Unable to encode object");
+        }
     }
 
     public BERConstructedOctetString(
-        DEREncodable  obj)
+        ASN1Encodable  obj)
     {
-        super(obj.getDERObject());
+        this(obj.toASN1Primitive());
     }
 
     public byte[] getOctets()
@@ -114,35 +129,7 @@
          return vec; 
     }
 
-    public void encode(
-        DEROutputStream out)
-        throws IOException
-    {
-        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
-        {
-            out.write(CONSTRUCTED | OCTET_STRING);
-
-            out.write(0x80);
-
-            //
-            // write out the octet array
-            //
-            Enumeration e = getObjects();
-            while (e.hasMoreElements())
-            {
-                out.writeObject(e.nextElement());
-            }
-
-            out.write(0x00);
-            out.write(0x00);
-        }
-        else
-        {
-            super.encode(out);
-        }
-    }
-
-    public static BERConstructedOctetString fromSequence(ASN1Sequence seq)
+    public static BEROctetString fromSequence(ASN1Sequence seq)
     {
         Vector      v = new Vector();
         Enumeration e = seq.getObjects();
diff --git a/src/main/java/org/bouncycastle/asn1/BERFactory.java b/src/main/java/org/bouncycastle/asn1/BERFactory.java
index 82f101c..023be0b 100644
--- a/src/main/java/org/bouncycastle/asn1/BERFactory.java
+++ b/src/main/java/org/bouncycastle/asn1/BERFactory.java
@@ -14,9 +14,4 @@
     {
         return v.size() < 1 ? EMPTY_SET : new BERSet(v);
     }
-
-    static BERSet createSet(ASN1EncodableVector v, boolean needsSorting)
-    {
-        return v.size() < 1 ? EMPTY_SET : new BERSet(v, needsSorting);
-    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/BEROctetString.java b/src/main/java/org/bouncycastle/asn1/BEROctetString.java
new file mode 100644
index 0000000..bc1ed44
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/BEROctetString.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class BEROctetString
+    extends ASN1OctetString
+{
+    private static final int MAX_LENGTH = 1000;
+
+    private ASN1OctetString[] octs;
+
+    /**
+     * convert a vector of octet strings into a single byte string
+     */
+    static private byte[] toBytes(
+        ASN1OctetString[]  octs)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != octs.length; i++)
+        {
+            try
+            {
+                DEROctetString o = (DEROctetString)octs[i];
+
+                bOut.write(o.getOctets());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IllegalArgumentException(octs[i].getClass().getName() + " found in input should only contain DEROctetString");
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("exception converting octets " + e.toString());
+            }
+        }
+
+        return bOut.toByteArray();
+    }
+
+    /**
+     * @param string the octets making up the octet string.
+     */
+    public BEROctetString(
+        byte[] string)
+    {
+        super(string);
+    }
+
+    public BEROctetString(
+        ASN1OctetString[] octs)
+    {
+        super(toBytes(octs));
+
+        this.octs = octs;
+    }
+
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    /**
+     * return the DER octets that make up this string.
+     */
+    public Enumeration getObjects()
+    {
+        if (octs == null)
+        {
+            return generateOcts().elements();
+        }
+
+        return new Enumeration()
+        {
+            int counter = 0;
+
+            public boolean hasMoreElements()
+            {
+                return counter < octs.length;
+            }
+
+            public Object nextElement()
+            {
+                return octs[counter++];
+            }
+        };
+    }
+
+    private Vector generateOcts()
+    { 
+        Vector vec = new Vector();
+        for (int i = 0; i < string.length; i += MAX_LENGTH) 
+        { 
+            int end; 
+
+            if (i + MAX_LENGTH > string.length) 
+            { 
+                end = string.length; 
+            } 
+            else 
+            { 
+                end = i + MAX_LENGTH; 
+            } 
+
+            byte[] nStr = new byte[end - i]; 
+
+            System.arraycopy(string, i, nStr, 0, nStr.length);
+
+            vec.addElement(new DEROctetString(nStr));
+         } 
+        
+         return vec; 
+    }
+
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = 0;
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+        }
+
+        return 2 + length + 2;
+    }
+
+    public void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+
+        out.write(0x80);
+
+        //
+        // write out the octet array
+        //
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            out.writeObject((ASN1Encodable)e.nextElement());
+        }
+
+        out.write(0x00);
+        out.write(0x00);
+    }
+
+    static BEROctetString fromSequence(ASN1Sequence seq)
+    {
+        ASN1OctetString[]     v = new ASN1OctetString[seq.size()];
+        Enumeration e = seq.getObjects();
+        int                   index = 0;
+
+        while (e.hasMoreElements())
+        {
+            v[index++] = (ASN1OctetString)e.nextElement();
+        }
+
+        return new BEROctetString(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java b/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
index 1118a56..1c7132e 100644
--- a/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
@@ -21,13 +21,13 @@
         return new ConstructedOctetStream(_parser);
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
-        return new BERConstructedOctetString(Streams.readAll(getOctetStream()));
+        return new BEROctetString(Streams.readAll(getOctetStream()));
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
index c2e8da4..7117d4f 100644
--- a/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
@@ -20,13 +20,13 @@
         {
             writeNull();
         }
-        else if (obj instanceof DERObject)
+        else if (obj instanceof ASN1Primitive)
         {
-            ((DERObject)obj).encode(this);
+            ((ASN1Primitive)obj).encode(this);
         }
-        else if (obj instanceof DEREncodable)
+        else if (obj instanceof ASN1Encodable)
         {
-            ((DEREncodable)obj).getDERObject().encode(this);
+            ((ASN1Encodable)obj).toASN1Primitive().encode(this);
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERSequence.java b/src/main/java/org/bouncycastle/asn1/BERSequence.java
index aec6fd6..aa44950 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSequence.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSequence.java
@@ -4,7 +4,7 @@
 import java.util.Enumeration;
 
 public class BERSequence
-    extends DERSequence
+    extends ASN1Sequence
 {
     /**
      * create an empty sequence
@@ -17,7 +17,7 @@
      * create a sequence containing one object
      */
     public BERSequence(
-        DEREncodable    obj)
+        ASN1Encodable obj)
     {
         super(obj);
     }
@@ -26,34 +26,48 @@
      * create a sequence containing a vector of objects.
      */
     public BERSequence(
-        ASN1EncodableVector   v)
+        ASN1EncodableVector v)
     {
         super(v);
     }
 
+    /**
+     * create a sequence containing an array of objects.
+     */
+    public BERSequence(
+        ASN1Encodable[]   array)
+    {
+        super(array);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = 0;
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+        }
+
+        return 2 + length + 2;
+    }
+
     /*
      */
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+        out.write(0x80);
+
+        Enumeration e = getObjects();
+        while (e.hasMoreElements())
         {
-            out.write(SEQUENCE | CONSTRUCTED);
-            out.write(0x80);
-            
-            Enumeration e = getObjects();
-            while (e.hasMoreElements())
-            {
-                out.writeObject(e.nextElement());
-            }
-        
-            out.write(0x00);
-            out.write(0x00);
+            out.writeObject((ASN1Encodable)e.nextElement());
         }
-        else
-        {
-            super.encode(out);
-        }
+
+        out.write(0x00);
+        out.write(0x00);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java b/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
index 4f3b7ec..d5d4395 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
@@ -12,19 +12,19 @@
         this._parser = parser;
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         return _parser.readObject();
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
         return new BERSequence(_parser.readVector());
     }
     
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERSet.java b/src/main/java/org/bouncycastle/asn1/BERSet.java
index a5a2633..064d778 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSet.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSet.java
@@ -4,7 +4,7 @@
 import java.util.Enumeration;
 
 public class BERSet
-    extends DERSet
+    extends ASN1Set
 {
     /**
      * create an empty sequence
@@ -14,10 +14,10 @@
     }
 
     /**
-     * create a set containing one object
+     * @param obj - a single object that makes up the set.
      */
     public BERSet(
-        DEREncodable    obj)
+        ASN1Encodable obj)
     {
         super(obj);
     }
@@ -26,44 +26,48 @@
      * @param v - a vector of objects making up the set.
      */
     public BERSet(
-        ASN1EncodableVector   v)
+        ASN1EncodableVector v)
     {
         super(v, false);
     }
 
     /**
-     * @param v - a vector of objects making up the set.
+     * create a set from an array of objects.
      */
-    BERSet(
-        ASN1EncodableVector  v,
-        boolean              needsSorting)
+    public BERSet(
+        ASN1Encodable[]   a)
     {
-        super(v, needsSorting);
+        super(a, false);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = 0;
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+        }
+
+        return 2 + length + 2;
     }
 
     /*
      */
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        out.write(BERTags.SET | BERTags.CONSTRUCTED);
+        out.write(0x80);
+
+        Enumeration e = getObjects();
+        while (e.hasMoreElements())
         {
-            out.write(SET | CONSTRUCTED);
-            out.write(0x80);
-            
-            Enumeration e = getObjects();
-            while (e.hasMoreElements())
-            {
-                out.writeObject(e.nextElement());
-            }
-        
-            out.write(0x00);
-            out.write(0x00);
+            out.writeObject((ASN1Encodable)e.nextElement());
         }
-        else
-        {
-            super.encode(out);
-        }
+
+        out.write(0x00);
+        out.write(0x00);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/BERSetParser.java b/src/main/java/org/bouncycastle/asn1/BERSetParser.java
index e345f3f..5a30f3c 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSetParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSetParser.java
@@ -12,19 +12,19 @@
         this._parser = parser;
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         return _parser.readObject();
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
-        return new BERSet(_parser.readVector(), false);
+        return new BERSet(_parser.readVector());
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java b/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
index e09c910..1af0a43 100644
--- a/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
+++ b/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
@@ -9,7 +9,7 @@
  * rules (as with sequences).
  */
 public class BERTaggedObject
-    extends DERTaggedObject
+    extends ASN1TaggedObject
 {
     /**
      * @param tagNo the tag number for this object.
@@ -17,9 +17,9 @@
      */
     public BERTaggedObject(
         int             tagNo,
-        DEREncodable    obj)
+        ASN1Encodable    obj)
     {
-        super(tagNo, obj);
+        super(true, tagNo, obj);
     }
 
     /**
@@ -30,7 +30,7 @@
     public BERTaggedObject(
         boolean         explicit,
         int             tagNo,
-        DEREncodable    obj)
+        ASN1Encodable    obj)
     {
         super(explicit, tagNo, obj);
     }
@@ -45,63 +45,103 @@
         super(false, tagNo, new BERSequence());
     }
 
-    void encode(
-        DEROutputStream  out)
-        throws IOException
+    boolean isConstructed()
     {
-        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        if (!empty)
         {
-            out.writeTag(CONSTRUCTED | TAGGED, tagNo);
-            out.write(0x80);
-
-            if (!empty)
+            if (explicit)
             {
-                if (!explicit)
-                {
-                    Enumeration e;
-                    if (obj instanceof ASN1OctetString)
-                    {
-                        if (obj instanceof BERConstructedOctetString)
-                        {
-                            e = ((BERConstructedOctetString)obj).getObjects();
-                        }
-                        else
-                        {
-                            ASN1OctetString             octs = (ASN1OctetString)obj;
-                            BERConstructedOctetString   berO = new BERConstructedOctetString(octs.getOctets());
-                            e = berO.getObjects();
-                        }
-                    }
-                    else if (obj instanceof ASN1Sequence)
-                    {
-                        e = ((ASN1Sequence)obj).getObjects();
-                    }
-                    else if (obj instanceof ASN1Set)
-                    {
-                        e = ((ASN1Set)obj).getObjects();
-                    }
-                    else
-                    {
-                        throw new RuntimeException("not implemented: " + obj.getClass().getName());
-                    }
-
-                    while (e.hasMoreElements())
-                    {
-                        out.writeObject(e.nextElement());
-                    }
-                }
-                else
-                {
-                    out.writeObject(obj);
-                }
+                return true;
             }
+            else
+            {
+                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
 
-            out.write(0x00);
-            out.write(0x00);
+                return primitive.isConstructed();
+            }
         }
         else
         {
-            super.encode(out);
+            return true;
         }
     }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive();
+            int length = primitive.encodedLength();
+
+            if (explicit)
+            {
+                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+            }
+            else
+            {
+                // header length already in calculation
+                length = length - 1;
+
+                return StreamUtil.calculateTagLength(tagNo) + length;
+            }
+        }
+        else
+        {
+            return StreamUtil.calculateTagLength(tagNo) + 1;
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+        out.write(0x80);
+
+        if (!empty)
+        {
+            if (!explicit)
+            {
+                Enumeration e;
+                if (obj instanceof ASN1OctetString)
+                {
+                    if (obj instanceof BEROctetString)
+                    {
+                        e = ((BEROctetString)obj).getObjects();
+                    }
+                    else
+                    {
+                        ASN1OctetString             octs = (ASN1OctetString)obj;
+                        BEROctetString berO = new BEROctetString(octs.getOctets());
+                        e = berO.getObjects();
+                    }
+                }
+                else if (obj instanceof ASN1Sequence)
+                {
+                    e = ((ASN1Sequence)obj).getObjects();
+                }
+                else if (obj instanceof ASN1Set)
+                {
+                    e = ((ASN1Set)obj).getObjects();
+                }
+                else
+                {
+                    throw new RuntimeException("not implemented: " + obj.getClass().getName());
+                }
+
+                while (e.hasMoreElements())
+                {
+                    out.writeObject((ASN1Encodable)e.nextElement());
+                }
+            }
+            else
+            {
+                out.writeObject(obj);
+            }
+        }
+
+        out.write(0x00);
+        out.write(0x00);
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java b/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
index 40333fb..7cd334a 100644
--- a/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
@@ -1,7 +1,6 @@
 package org.bouncycastle.asn1;
 
 import java.io.IOException;
-import java.io.InputStream;
 
 public class BERTaggedObjectParser
     implements ASN1TaggedObjectParser
@@ -10,17 +9,6 @@
     private int _tagNumber;
     private ASN1StreamParser _parser;
 
-    /**
-     * @deprecated
-     */
-    protected BERTaggedObjectParser(
-        int         baseTag,
-        int         tagNumber,
-        InputStream contentStream)
-    {
-        this((baseTag & DERTags.CONSTRUCTED) != 0, tagNumber, new ASN1StreamParser(contentStream));
-    }
-
     BERTaggedObjectParser(
         boolean             constructed,
         int                 tagNumber,
@@ -41,7 +29,7 @@
         return _tagNumber;
     }
 
-    public DEREncodable getObjectParser(
+    public ASN1Encodable getObjectParser(
         int     tag,
         boolean isExplicit)
         throws IOException
@@ -58,13 +46,13 @@
         return _parser.readImplicit(_constructed, tag);
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
         return _parser.readTaggedObject(_constructed, _tagNumber);
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERTags.java b/src/main/java/org/bouncycastle/asn1/BERTags.java
new file mode 100644
index 0000000..7281a6a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/BERTags.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1;
+
+public interface BERTags
+{
+    public static final int BOOLEAN             = 0x01;
+    public static final int INTEGER             = 0x02;
+    public static final int BIT_STRING          = 0x03;
+    public static final int OCTET_STRING        = 0x04;
+    public static final int NULL                = 0x05;
+    public static final int OBJECT_IDENTIFIER   = 0x06;
+    public static final int EXTERNAL            = 0x08;
+    public static final int ENUMERATED          = 0x0a;
+    public static final int SEQUENCE            = 0x10;
+    public static final int SEQUENCE_OF         = 0x10; // for completeness
+    public static final int SET                 = 0x11;
+    public static final int SET_OF              = 0x11; // for completeness
+
+
+    public static final int NUMERIC_STRING      = 0x12;
+    public static final int PRINTABLE_STRING    = 0x13;
+    public static final int T61_STRING          = 0x14;
+    public static final int VIDEOTEX_STRING     = 0x15;
+    public static final int IA5_STRING          = 0x16;
+    public static final int UTC_TIME            = 0x17;
+    public static final int GENERALIZED_TIME    = 0x18;
+    public static final int GRAPHIC_STRING      = 0x19;
+    public static final int VISIBLE_STRING      = 0x1a;
+    public static final int GENERAL_STRING      = 0x1b;
+    public static final int UNIVERSAL_STRING    = 0x1c;
+    public static final int BMP_STRING          = 0x1e;
+    public static final int UTF8_STRING         = 0x0c;
+    
+    public static final int CONSTRUCTED         = 0x20;
+    public static final int APPLICATION         = 0x40;
+    public static final int TAGGED              = 0x80;
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java b/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java
index 045cffd..f247b11 100644
--- a/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java
+++ b/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java
@@ -1,7 +1,7 @@
 package org.bouncycastle.asn1;
 
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 class ConstructedOctetStream
     extends InputStream
diff --git a/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java b/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
index 7ca06d6..5b59288 100644
--- a/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
+++ b/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
@@ -9,7 +9,7 @@
  * Base class for an application specific object
  */
 public class DERApplicationSpecific 
-    extends ASN1Object
+    extends ASN1Primitive
 {
     private final boolean   isConstructed;
     private final int       tag;
@@ -34,7 +34,7 @@
 
     public DERApplicationSpecific(
         int                  tag, 
-        DEREncodable         object) 
+        ASN1Encodable object)
         throws IOException 
     {
         this(true, tag, object);
@@ -43,12 +43,14 @@
     public DERApplicationSpecific(
         boolean      explicit,
         int          tag,
-        DEREncodable object)
+        ASN1Encodable object)
         throws IOException
     {
-        byte[] data = object.getDERObject().getDEREncoded();
+        ASN1Primitive primitive = object.toASN1Primitive();
 
-        this.isConstructed = explicit;
+        byte[] data = primitive.getEncoded(ASN1Encoding.DER);
+
+        this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence);
         this.tag = tag;
 
         if (explicit)
@@ -57,7 +59,7 @@
         }
         else
         {
-            int lenBytes = getLengthOfLength(data);
+            int lenBytes = getLengthOfHeader(data);
             byte[] tmp = new byte[data.length - lenBytes];
             System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
             this.octets = tmp;
@@ -74,7 +76,7 @@
         {
             try
             {
-                bOut.write(((ASN1Encodable)vec.get(i)).getEncoded());
+                bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER));
             }
             catch (IOException e)
             {
@@ -84,16 +86,59 @@
         this.octets = bOut.toByteArray();
     }
 
-    private int getLengthOfLength(byte[] data)
+    public static DERApplicationSpecific getInstance(Object obj)
     {
-        int count = 2;               // TODO: assumes only a 1 byte tag number
-
-        while((data[count - 1] & 0x80) != 0)
+        if (obj == null || obj instanceof DERApplicationSpecific)
         {
-            count++;
+            return (DERApplicationSpecific)obj;
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct object from byte[]: " + e.getMessage());
+            }
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1Sequence)
+            {
+                return (DERApplicationSpecific)primitive;
+            }
         }
 
-        return count;
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    private int getLengthOfHeader(byte[] data)
+    {
+        int length = data[1] & 0xff; // TODO: assumes 1 byte tag
+
+        if (length == 0x80)
+        {
+            return 2;      // indefinite-length encoding
+        }
+
+        if (length > 127)
+        {
+            int size = length & 0x7f;
+
+            // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+            if (size > 4)
+            {
+                throw new IllegalStateException("DER length more than 4 bytes: " + size);
+            }
+
+            return size + 2;
+        }
+
+        return 2;
     }
 
     public boolean isConstructed()
@@ -117,7 +162,7 @@
      * @return  the resulting object
      * @throws IOException if reconstruction fails.
      */
-    public DERObject getObject() 
+    public ASN1Primitive getObject()
         throws IOException 
     {
         return new ASN1InputStream(getContents()).readObject();
@@ -130,7 +175,7 @@
      * @return  the resulting object
      * @throws IOException if reconstruction fails.
      */
-    public DERObject getObject(int derTagNo)
+    public ASN1Primitive getObject(int derTagNo)
         throws IOException
     {
         if (derTagNo >= 0x1f)
@@ -141,30 +186,36 @@
         byte[] orig = this.getEncoded();
         byte[] tmp = replaceTagNumber(derTagNo, orig);
 
-        if ((orig[0] & DERTags.CONSTRUCTED) != 0)
+        if ((orig[0] & BERTags.CONSTRUCTED) != 0)
         {
-            tmp[0] |= DERTags.CONSTRUCTED;
+            tmp[0] |= BERTags.CONSTRUCTED;
         }
 
         return new ASN1InputStream(tmp).readObject();
     }
-    
-    /* (non-Javadoc)
-     * @see org.bouncycastle.asn1.DERObject#encode(org.bouncycastle.asn1.DEROutputStream)
-     */
-    void encode(DEROutputStream out) throws IOException
+
+    int encodedLength()
+        throws IOException
     {
-        int classBits = DERTags.APPLICATION;
+        return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out) throws IOException
+    {
+        int classBits = BERTags.APPLICATION;
         if (isConstructed)
         {
-            classBits |= DERTags.CONSTRUCTED; 
+            classBits |= BERTags.CONSTRUCTED;
         }
 
         out.writeEncoded(classBits, tag, octets);
     }
     
     boolean asn1Equals(
-        DERObject o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERApplicationSpecific))
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/src/main/java/org/bouncycastle/asn1/DERBMPString.java
index 1ff72de..33a09f8 100644
--- a/src/main/java/org/bouncycastle/asn1/DERBMPString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERBMPString.java
@@ -2,14 +2,16 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+
 /**
  * DER BMPString object.
  */
 public class DERBMPString
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    String  string;
+    private char[]  string;
 
     /**
      * return a BMP String from the given object.
@@ -41,7 +43,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERBMPString)
         {
@@ -52,12 +54,11 @@
             return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());
         }
     }
-    
 
     /**
      * basic constructor - byte encoded string.
      */
-    public DERBMPString(
+    DERBMPString(
         byte[]   string)
     {
         char[]  cs = new char[string.length / 2];
@@ -67,7 +68,12 @@
             cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
         }
 
-        this.string = new String(cs);
+        this.string = cs;
+    }
+
+    DERBMPString(char[] string)
+    {
+        this.string = string;
     }
 
     /**
@@ -76,26 +82,26 @@
     public DERBMPString(
         String   string)
     {
-        this.string = string;
+        this.string = string.toCharArray();
     }
 
     public String getString()
     {
-        return string;
+        return new String(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 
     protected boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERBMPString))
         {
@@ -104,22 +110,32 @@
 
         DERBMPString  s = (DERBMPString)o;
 
-        return this.getString().equals(s.getString());
+        return Arrays.areEqual(string, s.string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2);
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        char[]  c = string.toCharArray();
-        byte[]  b = new byte[c.length * 2];
+        out.write(BERTags.BMP_STRING);
+        out.writeLength(string.length * 2);
 
-        for (int i = 0; i != c.length; i++)
+        for (int i = 0; i != string.length; i++)
         {
-            b[2 * i] = (byte)(c[i] >> 8);
-            b[2 * i + 1] = (byte)c[i];
-        }
+            char c = string[i];
 
-        out.writeEncoded(BMP_STRING, b);
+            out.write((byte)(c >> 8));
+            out.write((byte)c);
+        }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERBitString.java b/src/main/java/org/bouncycastle/asn1/DERBitString.java
index efca7d3..f7f2462 100644
--- a/src/main/java/org/bouncycastle/asn1/DERBitString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERBitString.java
@@ -1,13 +1,16 @@
 package org.bouncycastle.asn1;
 
 import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
 import java.io.IOException;
+import java.io.InputStream;
 
 import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.io.Streams;
 
 public class DERBitString
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
     private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
     
@@ -116,7 +119,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERBitString)
         {
@@ -156,11 +159,11 @@
     }
 
     public DERBitString(
-        DEREncodable  obj)
+        ASN1Encodable  obj)
     {
         try
         {
-            this.data = obj.getDERObject().getEncoded(ASN1Encodable.DER);
+            this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
             this.padBits = 0;
         }
         catch (IOException e)
@@ -194,9 +197,19 @@
         
         return value;
     }
-    
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
+    }
+
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream  out)
         throws IOException
     {
         byte[]  bytes = new byte[getBytes().length + 1];
@@ -204,7 +217,7 @@
         bytes[0] = (byte)getPadBits();
         System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
 
-        out.writeEncoded(BIT_STRING, bytes);
+        out.writeEncoded(BERTags.BIT_STRING, bytes);
     }
 
     public int hashCode()
@@ -213,7 +226,7 @@
     }
 
     protected boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive  o)
     {
         if (!(o instanceof DERBitString))
         {
@@ -274,4 +287,26 @@
 
         return new DERBitString(data, padBits);
     }
+
+    static DERBitString fromInputStream(int length, InputStream stream)
+        throws IOException
+    {
+        if (length < 1)
+        {
+            throw new IllegalArgumentException("truncated BIT STRING detected");
+        }
+
+        int padBits = stream.read();
+        byte[] data = new byte[length - 1];
+
+        if (data.length != 0)
+        {
+            if (Streams.readFully(stream, data) != data.length)
+            {
+                throw new EOFException("EOF encountered in middle of BIT STRING");
+            }
+        }
+
+        return new DERBitString(data, padBits);
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/src/main/java/org/bouncycastle/asn1/DERBoolean.java
index 5cba346..a519fa2 100644
--- a/src/main/java/org/bouncycastle/asn1/DERBoolean.java
+++ b/src/main/java/org/bouncycastle/asn1/DERBoolean.java
@@ -2,27 +2,38 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+
 public class DERBoolean
-    extends ASN1Object
+    extends ASN1Primitive
 {
+    private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
+    private static final byte[] FALSE_VALUE = new byte[] { 0 };
+
     // BEGIN android-changed
-    private final byte  value;
+    final private byte[]         value;
     // END android-changed
 
-    public static final DERBoolean FALSE = new DERBoolean(false);
-    public static final DERBoolean TRUE  = new DERBoolean(true);
+    public static final ASN1Boolean FALSE = new ASN1Boolean(false);
+    public static final ASN1Boolean TRUE  = new ASN1Boolean(true);
+
 
     /**
      * return a boolean from the passed in object.
      *
      * @exception IllegalArgumentException if the object cannot be converted.
      */
-    public static DERBoolean getInstance(
+    public static ASN1Boolean getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof DERBoolean)
+        if (obj == null || obj instanceof ASN1Boolean)
         {
-            return (DERBoolean)obj;
+            return (ASN1Boolean)obj;
+        }
+
+        if (obj instanceof DERBoolean)
+        {
+            return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -31,7 +42,7 @@
     /**
      * return a DERBoolean from the passed in boolean.
      */
-    public static DERBoolean getInstance(
+    public static ASN1Boolean getInstance(
         boolean  value)
     {
         return (value ? TRUE : FALSE);
@@ -46,8 +57,8 @@
     {
         return (octets[0] != 0) ? TRUE : FALSE;
     }
-    // END android-added
 
+    // END android-added
     /**
      * return a Boolean from a tagged object.
      *
@@ -61,7 +72,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERBoolean)
         {
@@ -69,68 +80,104 @@
         }
         else
         {
-            // BEGIN android-changed
-            return getInstance(((ASN1OctetString)o).getOctets());
-            // END android-changed
+            return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
         }
     }
     
-    // BEGIN android-removed
-    // public DERBoolean(
-    //     byte[]       value)
-    // {
-    //     if (value.length != 1)
-    //     {
-    //         throw new IllegalArgumentException("byte value should have 1 byte in it");
-    //     }
-    //
-    //     this.value = value[0];
-    // }
-    // END android-removed
+    // BEGIN android-changed
+    protected DERBoolean(
+    // END android-changed
+        byte[]       value)
+    {
+        if (value.length != 1)
+        {
+            throw new IllegalArgumentException("byte value should have 1 byte in it");
+        }
+
+        if (value[0] == 0)
+        {
+            this.value = FALSE_VALUE;
+        }
+        else if (value[0] == 0xff)
+        {
+            this.value = TRUE_VALUE;
+        }
+        else
+        {
+            this.value = Arrays.clone(value);
+        }
+    }
 
     // BEGIN android-changed
     protected DERBoolean(
         boolean     value)
     // END android-changed
     {
-        this.value = (value) ? (byte)0xff : (byte)0;
+        this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
     }
 
     public boolean isTrue()
     {
-        return (value != 0);
+        return (value[0] != 0);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 3;
     }
 
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        byte[]  bytes = new byte[1];
-
-        bytes[0] = value;
-
-        out.writeEncoded(BOOLEAN, bytes);
+        out.writeEncoded(BERTags.BOOLEAN, value);
     }
     
     protected boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive  o)
     {
         if ((o == null) || !(o instanceof DERBoolean))
         {
             return false;
         }
 
-        return (value == ((DERBoolean)o).value);
+        return (value[0] == ((DERBoolean)o).value[0]);
     }
     
     public int hashCode()
     {
-        return value;
+        return value[0];
     }
 
 
     public String toString()
     {
-      return (value != 0) ? "TRUE" : "FALSE";
+      return (value[0] != 0) ? "TRUE" : "FALSE";
+    }
+
+    static ASN1Boolean fromOctetString(byte[] value)
+    {
+        if (value.length != 1)
+        {
+            throw new IllegalArgumentException("byte value should have 1 byte in it");
+        }
+
+        if (value[0] == 0)
+        {
+            return FALSE;
+        }
+        else if (value[0] == 0xff)
+        {
+            return TRUE;
+        }
+        else
+        {
+            return new ASN1Boolean(value);
+        }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DEREncodable.java b/src/main/java/org/bouncycastle/asn1/DEREncodable.java
deleted file mode 100644
index d89305a..0000000
--- a/src/main/java/org/bouncycastle/asn1/DEREncodable.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.bouncycastle.asn1;
-
-public interface DEREncodable
-{
-    public DERObject getDERObject();
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java b/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
index 68d63eb..919ff72 100644
--- a/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
+++ b/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
@@ -1,16 +1,13 @@
 package org.bouncycastle.asn1;
 
-import java.util.Vector;
-
 /**
  * a general class for building up a vector of DER encodable objects -
  * this will eventually be superceded by ASN1EncodableVector so you should
  * use that class in preference.
  */
 public class DEREncodableVector
+    extends ASN1EncodableVector
 {
-    Vector v = new Vector();
-
     /**
      * @deprecated use ASN1EncodableVector instead.
      */
@@ -18,21 +15,4 @@
     {
 
     }
-    
-    public void add(
-        DEREncodable   obj)
-    {
-        v.addElement(obj);
-    }
-
-    public DEREncodable get(
-        int i)
-    {
-        return (DEREncodable)v.elementAt(i);
-    }
-
-    public int size()
-    {
-        return v.size();
-    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
index 440744e..2cf17f1 100644
--- a/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
+++ b/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
@@ -6,7 +6,7 @@
 import org.bouncycastle.util.Arrays;
 
 public class DEREnumerated
-    extends ASN1Object
+    extends ASN1Primitive
 {
     byte[]      bytes;
 
@@ -15,12 +15,17 @@
      *
      * @exception IllegalArgumentException if the object cannot be converted.
      */
-    public static DEREnumerated getInstance(
+    public static ASN1Enumerated getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof DEREnumerated)
+        if (obj == null || obj instanceof ASN1Enumerated)
         {
-            return (DEREnumerated)obj;
+            return (ASN1Enumerated)obj;
+        }
+
+        if (obj instanceof DEREnumerated)
+        {
+            return new ASN1Enumerated(((DEREnumerated)obj).getValue());
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -39,7 +44,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DEREnumerated)
         {
@@ -47,7 +52,7 @@
         }
         else
         {
-            return new DEREnumerated(((ASN1OctetString)o).getOctets());
+            return fromOctetString(((ASN1OctetString)o).getOctets());
         }
     }
 
@@ -74,15 +79,25 @@
         return new BigInteger(bytes);
     }
 
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
+    }
+
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(ENUMERATED, bytes);
+        out.writeEncoded(BERTags.ENUMERATED, bytes);
     }
     
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive  o)
     {
         if (!(o instanceof DEREnumerated))
         {
@@ -98,4 +113,34 @@
     {
         return Arrays.hashCode(bytes);
     }
+
+    private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
+
+    static ASN1Enumerated fromOctetString(byte[] enc)
+    {
+        if (enc.length > 1)
+        {
+            return new ASN1Enumerated(Arrays.clone(enc));
+        }
+
+        if (enc.length == 0)
+        {
+            throw new IllegalArgumentException("ENUMERATED has zero length");
+        }
+        int value = enc[0] & 0xff;
+
+        if (value >= cache.length)
+        {
+            return new ASN1Enumerated(Arrays.clone(enc));
+        }
+
+        ASN1Enumerated possibleMatch = cache[value];
+
+        if (possibleMatch == null)
+        {
+            possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
+        }
+
+        return possibleMatch;
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERExternal.java b/src/main/java/org/bouncycastle/asn1/DERExternal.java
index 769c945..aed1d27 100644
--- a/src/main/java/org/bouncycastle/asn1/DERExternal.java
+++ b/src/main/java/org/bouncycastle/asn1/DERExternal.java
@@ -7,34 +7,34 @@
  * Class representing the DER-type External
  */
 public class DERExternal
-    extends ASN1Object
+    extends ASN1Primitive
 {
-    private DERObjectIdentifier directReference;
-    private DERInteger indirectReference;
-    private ASN1Object dataValueDescriptor;
+    private ASN1ObjectIdentifier directReference;
+    private ASN1Integer indirectReference;
+    private ASN1Primitive dataValueDescriptor;
     private int encoding;
-    private DERObject externalContent;
+    private ASN1Primitive externalContent;
     
     public DERExternal(ASN1EncodableVector vector)
     {
         int offset = 0;
 
-        DERObject enc = getObjFromVector(vector, offset);
-        if (enc instanceof DERObjectIdentifier)
+        ASN1Primitive enc = getObjFromVector(vector, offset);
+        if (enc instanceof ASN1ObjectIdentifier)
         {
-            directReference = (DERObjectIdentifier)enc;
+            directReference = (ASN1ObjectIdentifier)enc;
             offset++;
             enc = getObjFromVector(vector, offset);
         }
-        if (enc instanceof DERInteger)
+        if (enc instanceof ASN1Integer)
         {
-            indirectReference = (DERInteger) enc;
+            indirectReference = (ASN1Integer) enc;
             offset++;
             enc = getObjFromVector(vector, offset);
         }
         if (!(enc instanceof DERTaggedObject))
         {
-            dataValueDescriptor = (ASN1Object) enc;
+            dataValueDescriptor = (ASN1Primitive) enc;
             offset++;
             enc = getObjFromVector(vector, offset);
         }
@@ -53,14 +53,14 @@
         externalContent = obj.getObject();
     }
 
-    private DERObject getObjFromVector(ASN1EncodableVector v, int index)
+    private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)
     {
         if (v.size() <= index)
         {
             throw new IllegalArgumentException("too few objects in input vector");
         }
 
-        return v.get(index).getDERObject();
+        return v.get(index).toASN1Primitive();
     }
     /**
      * Creates a new instance of DERExternal
@@ -70,9 +70,9 @@
      * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
      * @param externalData The external data in its encoded form.
      */
-    public DERExternal(DERObjectIdentifier directReference, DERInteger indirectReference, ASN1Object dataValueDescriptor, DERTaggedObject externalData)
+    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
     {
-        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.getDERObject());
+        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
     }
 
     /**
@@ -84,13 +84,13 @@
      * @param encoding The encoding to be used for the external data
      * @param externalData The external data
      */
-    public DERExternal(DERObjectIdentifier directReference, DERInteger indirectReference, ASN1Object dataValueDescriptor, int encoding, DERObject externalData)
+    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
     {
         setDirectReference(directReference);
         setIndirectReference(indirectReference);
         setDataValueDescriptor(dataValueDescriptor);
         setEncoding(encoding);
-        setExternalContent(externalData.getDERObject());
+        setExternalContent(externalData.toASN1Primitive());
     }
 
     /* (non-Javadoc)
@@ -115,34 +115,45 @@
         return ret;
     }
 
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        return this.getEncoded().length;
+    }
+
     /* (non-Javadoc)
-     * @see org.bouncycastle.asn1.DERObject#encode(org.bouncycastle.asn1.DEROutputStream)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
      */
-    void encode(DEROutputStream out)
+    void encode(ASN1OutputStream out)
         throws IOException
     {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         if (directReference != null)
         {
-            baos.write(directReference.getDEREncoded());
+            baos.write(directReference.getEncoded(ASN1Encoding.DER));
         }
         if (indirectReference != null)
         {
-            baos.write(indirectReference.getDEREncoded());
+            baos.write(indirectReference.getEncoded(ASN1Encoding.DER));
         }
         if (dataValueDescriptor != null)
         {
-            baos.write(dataValueDescriptor.getDEREncoded());
+            baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));
         }
-        DERTaggedObject obj = new DERTaggedObject(encoding, externalContent);
-        baos.write(obj.getDEREncoded());
-        out.writeEncoded(DERTags.CONSTRUCTED, DERTags.EXTERNAL, baos.toByteArray());
+        DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
+        baos.write(obj.getEncoded(ASN1Encoding.DER));
+        out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
     }
 
     /* (non-Javadoc)
-     * @see org.bouncycastle.asn1.ASN1Object#asn1Equals(org.bouncycastle.asn1.DERObject)
+     * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive)
      */
-    boolean asn1Equals(DERObject o)
+    boolean asn1Equals(ASN1Primitive o)
     {
         if (!(o instanceof DERExternal))
         {
@@ -181,7 +192,7 @@
      * Returns the data value descriptor
      * @return The descriptor
      */
-    public ASN1Object getDataValueDescriptor()
+    public ASN1Primitive getDataValueDescriptor()
     {
         return dataValueDescriptor;
     }
@@ -190,7 +201,7 @@
      * Returns the direct reference of the external element
      * @return The reference
      */
-    public DERObjectIdentifier getDirectReference()
+    public ASN1ObjectIdentifier getDirectReference()
     {
         return directReference;
     }
@@ -213,7 +224,7 @@
      * Returns the content of this element
      * @return The content
      */
-    public DERObject getExternalContent()
+    public ASN1Primitive getExternalContent()
     {
         return externalContent;
     }
@@ -222,7 +233,7 @@
      * Returns the indirect reference of this element
      * @return The reference
      */
-    public DERInteger getIndirectReference()
+    public ASN1Integer getIndirectReference()
     {
         return indirectReference;
     }
@@ -231,7 +242,7 @@
      * Sets the data value descriptor
      * @param dataValueDescriptor The descriptor
      */
-    private void setDataValueDescriptor(ASN1Object dataValueDescriptor)
+    private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor)
     {
         this.dataValueDescriptor = dataValueDescriptor;
     }
@@ -240,7 +251,7 @@
      * Sets the direct reference of the external element
      * @param directReferemce The reference
      */
-    private void setDirectReference(DERObjectIdentifier directReferemce)
+    private void setDirectReference(ASN1ObjectIdentifier directReferemce)
     {
         this.directReference = directReferemce;
     }
@@ -267,7 +278,7 @@
      * Sets the content of this element
      * @param externalContent The content
      */
-    private void setExternalContent(DERObject externalContent)
+    private void setExternalContent(ASN1Primitive externalContent)
     {
         this.externalContent = externalContent;
     }
@@ -276,7 +287,7 @@
      * Sets the indirect reference of this element
      * @param indirectReference The reference
      */
-    private void setIndirectReference(DERInteger indirectReference)
+    private void setIndirectReference(ASN1Integer indirectReference)
     {
         this.indirectReference = indirectReference;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/DERExternalParser.java b/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
index 059908f..b19c84d 100644
--- a/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
@@ -3,7 +3,7 @@
 import java.io.IOException;
 
 public class DERExternalParser
-    implements DEREncodable, InMemoryRepresentable
+    implements ASN1Encodable, InMemoryRepresentable
 {
     private ASN1StreamParser _parser;
 
@@ -15,13 +15,13 @@
         this._parser = parser;
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         return _parser.readObject();
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
         try
@@ -34,7 +34,7 @@
         }
     }
     
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try 
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERFactory.java b/src/main/java/org/bouncycastle/asn1/DERFactory.java
index 7364282..b829e3b 100644
--- a/src/main/java/org/bouncycastle/asn1/DERFactory.java
+++ b/src/main/java/org/bouncycastle/asn1/DERFactory.java
@@ -2,21 +2,16 @@
 
 class DERFactory
 {
-    static final DERSequence EMPTY_SEQUENCE = new DERSequence();
-    static final DERSet EMPTY_SET = new DERSet();
+    static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence();
+    static final ASN1Set EMPTY_SET = new DERSet();
 
-    static DERSequence createSequence(ASN1EncodableVector v)
+    static ASN1Sequence createSequence(ASN1EncodableVector v)
     {
-        return v.size() < 1 ? EMPTY_SEQUENCE : new DERSequence(v);
+        return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v);
     }
 
-    static DERSet createSet(ASN1EncodableVector v)
+    static ASN1Set createSet(ASN1EncodableVector v)
     {
-        return v.size() < 1 ? EMPTY_SET : new DERSet(v);
-    }
-
-    static DERSet createSet(ASN1EncodableVector v, boolean needsSorting)
-    {
-        return v.size() < 1 ? EMPTY_SET : new DERSet(v, needsSorting);
+        return v.size() < 1 ? EMPTY_SET : new DLSet(v);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
index 51d4658..d7cd594 100644
--- a/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
@@ -2,10 +2,14 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 public class DERGeneralString 
-    extends ASN1Object implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    private String string;
+    private byte[] string;
 
     public static DERGeneralString getInstance(
         Object obj) 
@@ -23,7 +27,7 @@
         ASN1TaggedObject obj, 
         boolean explicit) 
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERGeneralString)
         {
@@ -35,60 +39,60 @@
         }
     }
 
-    public DERGeneralString(byte[] string) 
+    DERGeneralString(byte[] string)
     {
-        char[] cs = new char[string.length];
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(string[i] & 0xff);
-        }
-        this.string = new String(cs);
+        this.string = string;
     }
 
     public DERGeneralString(String string) 
     {
-        this.string = string;
+        this.string = Strings.toByteArray(string);
     }
     
     public String getString() 
     {
-        return string;
+        return Strings.fromByteArray(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     public byte[] getOctets() 
     {
-        char[] cs = string.toCharArray();
-        byte[] bs = new byte[cs.length];
-        for (int i = 0; i != cs.length; i++) 
-        {
-            bs[i] = (byte) cs[i];
-        }
-        return bs;
+        return Arrays.clone(string);
     }
-    
-    void encode(DEROutputStream out) 
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(ASN1OutputStream out)
         throws IOException 
     {
-        out.writeEncoded(GENERAL_STRING, this.getOctets());
+        out.writeEncoded(BERTags.GENERAL_STRING, string);
     }
     
     public int hashCode() 
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
     
-    boolean asn1Equals(DERObject o)
+    boolean asn1Equals(ASN1Primitive o)
     {
         if (!(o instanceof DERGeneralString)) 
         {
             return false;
         }
-        DERGeneralString s = (DERGeneralString) o;
-        return this.getString().equals(s.getString());
+        DERGeneralString s = (DERGeneralString)o;
+
+        return Arrays.areEqual(string, s.string);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
index 728cb22..bb3b575 100644
--- a/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
+++ b/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
@@ -7,25 +7,33 @@
 import java.util.SimpleTimeZone;
 import java.util.TimeZone;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * Generalized time object.
  */
 public class DERGeneralizedTime
-    extends ASN1Object
+    extends ASN1Primitive
 {
-    String      time;
+    private byte[]      time;
 
     /**
      * return a generalized time from the passed in object
      *
      * @exception IllegalArgumentException if the object cannot be converted.
      */
-    public static DERGeneralizedTime getInstance(
+    public static ASN1GeneralizedTime getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof DERGeneralizedTime)
+        if (obj == null || obj instanceof ASN1GeneralizedTime)
         {
-            return (DERGeneralizedTime)obj;
+            return (ASN1GeneralizedTime)obj;
+        }
+
+        if (obj instanceof DERGeneralizedTime)
+        {
+            return new ASN1GeneralizedTime(((DERGeneralizedTime)obj).time);
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -40,11 +48,11 @@
      * @exception IllegalArgumentException if the tagged object cannot
      *               be converted.
      */
-    public static DERGeneralizedTime getInstance(
+    public static ASN1GeneralizedTime getInstance(
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERGeneralizedTime)
         {
@@ -52,7 +60,7 @@
         }
         else
         {
-            return new DERGeneralizedTime(((ASN1OctetString)o).getOctets());
+            return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
         }
     }
     
@@ -68,7 +76,7 @@
     public DERGeneralizedTime(
         String  time)
     {
-        this.time = time;
+        this.time = Strings.toByteArray(time);
         try
         {
             this.getDate();
@@ -80,7 +88,7 @@
     }
 
     /**
-     * base constructer from a java.util.date object
+     * base constructor from a java.util.date object
      */
     public DERGeneralizedTime(
         Date time)
@@ -89,23 +97,13 @@
 
         dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
 
-        this.time = dateF.format(time);
+        this.time = Strings.toByteArray(dateF.format(time));
     }
 
     DERGeneralizedTime(
         byte[]  bytes)
     {
-        //
-        // explicitly convert to characters
-        //
-        char[]  dateC = new char[bytes.length];
-
-        for (int i = 0; i != dateC.length; i++)
-        {
-            dateC[i] = (char)(bytes[i] & 0xff);
-        }
-
-        this.time = new String(dateC);
+        this.time = bytes;
     }
 
     /**
@@ -114,7 +112,7 @@
      */
     public String getTimeString()
     {
-        return time;
+        return Strings.fromByteArray(time);
     }
     
     /**
@@ -131,39 +129,41 @@
      */
     public String getTime()
     {
+        String stime = Strings.fromByteArray(time);
+
         //
         // standardise the format.
         //             
-        if (time.charAt(time.length() - 1) == 'Z')
+        if (stime.charAt(stime.length() - 1) == 'Z')
         {
-            return time.substring(0, time.length() - 1) + "GMT+00:00";
+            return stime.substring(0, stime.length() - 1) + "GMT+00:00";
         }
         else
         {
-            int signPos = time.length() - 5;
-            char sign = time.charAt(signPos);
+            int signPos = stime.length() - 5;
+            char sign = stime.charAt(signPos);
             if (sign == '-' || sign == '+')
             {
-                return time.substring(0, signPos)
+                return stime.substring(0, signPos)
                     + "GMT"
-                    + time.substring(signPos, signPos + 3)
+                    + stime.substring(signPos, signPos + 3)
                     + ":"
-                    + time.substring(signPos + 3);
+                    + stime.substring(signPos + 3);
             }
             else
             {
-                signPos = time.length() - 3;
-                sign = time.charAt(signPos);
+                signPos = stime.length() - 3;
+                sign = stime.charAt(signPos);
                 if (sign == '-' || sign == '+')
                 {
-                    return time.substring(0, signPos)
+                    return stime.substring(0, signPos)
                         + "GMT"
-                        + time.substring(signPos)
+                        + stime.substring(signPos)
                         + ":00";
                 }
             }
         }            
-        return time + calculateGMTOffset();
+        return stime + calculateGMTOffset();
     }
 
     private String calculateGMTOffset()
@@ -208,9 +208,10 @@
         throws ParseException
     {
         SimpleDateFormat dateF;
-        String d = time;
+        String stime = Strings.fromByteArray(time);
+        String d = stime;
 
-        if (time.endsWith("Z"))
+        if (stime.endsWith("Z"))
         {
             if (hasFractionalSeconds())
             {
@@ -223,7 +224,7 @@
 
             dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
         }
-        else if (time.indexOf('-') > 0 || time.indexOf('+') > 0)
+        else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
         {
             d = this.getTime();
             if (hasFractionalSeconds())
@@ -287,43 +288,51 @@
 
     private boolean hasFractionalSeconds()
     {
-        return time.indexOf('.') == 14;
-    }
-
-    private byte[] getOctets()
-    {
-        char[]  cs = time.toCharArray();
-        byte[]  bs = new byte[cs.length];
-
-        for (int i = 0; i != cs.length; i++)
+        for (int i = 0; i != time.length; i++)
         {
-            bs[i] = (byte)cs[i];
+            if (time[i] == '.')
+            {
+                if (i == 14)
+                {
+                    return true;
+                }
+            }
         }
-
-        return bs;
+        return false;
     }
 
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        int length = time.length;
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream  out)
         throws IOException
     {
-        out.writeEncoded(GENERALIZED_TIME, this.getOctets());
+        out.writeEncoded(BERTags.GENERALIZED_TIME, time);
     }
     
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive  o)
     {
         if (!(o instanceof DERGeneralizedTime))
         {
             return false;
         }
 
-        return time.equals(((DERGeneralizedTime)o).time);
+        return Arrays.areEqual(time, ((DERGeneralizedTime)o).time);
     }
     
     public int hashCode()
     {
-        return time.hashCode();
+        return Arrays.hashCode(time);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/src/main/java/org/bouncycastle/asn1/DERIA5String.java
index e94c62b..abb2811 100644
--- a/src/main/java/org/bouncycastle/asn1/DERIA5String.java
+++ b/src/main/java/org/bouncycastle/asn1/DERIA5String.java
@@ -2,14 +2,17 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * DER IA5String object - this is an ascii string.
  */
 public class DERIA5String
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    String  string;
+    private byte[]  string;
 
     /**
      * return a IA5 string from the passed in object
@@ -40,7 +43,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERIA5String)
         {
@@ -55,17 +58,10 @@
     /**
      * basic constructor - with bytes.
      */
-    public DERIA5String(
+    DERIA5String(
         byte[]   string)
     {
-        char[]  cs = new char[string.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(string[i] & 0xff);
-        }
-
-        this.string = new String(cs);
+        this.string = string;
     }
 
     /**
@@ -98,46 +94,48 @@
             throw new IllegalArgumentException("string contains illegal characters");
         }
 
-        this.string = string;
+        this.string = Strings.toByteArray(string);
     }
 
     public String getString()
     {
-        return string;
+        return Strings.fromByteArray(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     public byte[] getOctets()
     {
-        char[]  cs = string.toCharArray();
-        byte[]  bs = new byte[cs.length];
+        return Arrays.clone(string);
+    }
 
-        for (int i = 0; i != cs.length; i++)
-        {
-            bs[i] = (byte)cs[i];
-        }
+    boolean isConstructed()
+    {
+        return false;
+    }
 
-        return bs; 
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(IA5_STRING, this.getOctets());
+        out.writeEncoded(BERTags.IA5_STRING, string);
     }
 
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERIA5String))
         {
@@ -146,7 +144,7 @@
 
         DERIA5String  s = (DERIA5String)o;
 
-        return this.getString().equals(s.getString());
+        return Arrays.areEqual(string, s.string);
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERInteger.java b/src/main/java/org/bouncycastle/asn1/DERInteger.java
index c72a6cb..d5e826d 100644
--- a/src/main/java/org/bouncycastle/asn1/DERInteger.java
+++ b/src/main/java/org/bouncycastle/asn1/DERInteger.java
@@ -6,7 +6,7 @@
 import org.bouncycastle.util.Arrays;
 
 public class DERInteger
-    extends ASN1Object
+    extends ASN1Primitive
 {
     byte[]      bytes;
 
@@ -15,12 +15,16 @@
      *
      * @exception IllegalArgumentException if the object cannot be converted.
      */
-    public static DERInteger getInstance(
+    public static ASN1Integer getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof DERInteger)
+        if (obj == null || obj instanceof ASN1Integer)
         {
-            return (DERInteger)obj;
+            return (ASN1Integer)obj;
+        }
+        if (obj instanceof DERInteger)
+        {
+            return new ASN1Integer((((DERInteger)obj).getValue()));
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -35,11 +39,11 @@
      * @exception IllegalArgumentException if the tagged object cannot
      *               be converted.
      */
-    public static DERInteger getInstance(
+    public static ASN1Integer getInstance(
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERInteger)
         {
@@ -83,11 +87,21 @@
         return new BigInteger(1, bytes);
     }
 
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
+    }
+
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(INTEGER, bytes);
+        out.writeEncoded(BERTags.INTEGER, bytes);
     }
     
     public int hashCode()
@@ -103,7 +117,7 @@
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive  o)
     {
         if (!(o instanceof DERInteger))
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERNull.java b/src/main/java/org/bouncycastle/asn1/DERNull.java
index c945f5c..9bbc826 100644
--- a/src/main/java/org/bouncycastle/asn1/DERNull.java
+++ b/src/main/java/org/bouncycastle/asn1/DERNull.java
@@ -10,9 +10,7 @@
 {
     public static final DERNull INSTANCE = new DERNull();
 
-    // BEGIN android-changed
     private static final byte[]  zeroBytes = new byte[0];
-    // END android-changed
 
     // BEGIN android-changed
     protected DERNull()
@@ -20,10 +18,20 @@
     {
     }
 
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 2;
+    }
+
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(NULL, zeroBytes);
+        out.writeEncoded(BERTags.NULL, zeroBytes);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/src/main/java/org/bouncycastle/asn1/DERNumericString.java
index 23314a6..fae4063 100644
--- a/src/main/java/org/bouncycastle/asn1/DERNumericString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERNumericString.java
@@ -2,14 +2,17 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
  */
 public class DERNumericString
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    String  string;
+    private byte[]  string;
 
     /**
      * return a Numeric string from the passed in object
@@ -40,7 +43,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERNumericString)
         {
@@ -55,17 +58,10 @@
     /**
      * basic constructor - with bytes.
      */
-    public DERNumericString(
+    DERNumericString(
         byte[]   string)
     {
-        char[]  cs = new char[string.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(string[i] & 0xff);
-        }
-
-        this.string = new String(cs);
+        this.string = string;
     }
 
     /**
@@ -94,46 +90,48 @@
             throw new IllegalArgumentException("string contains illegal characters");
         }
 
-        this.string = string;
+        this.string = Strings.toByteArray(string);
     }
 
     public String getString()
     {
-        return string;
+        return Strings.fromByteArray(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     public byte[] getOctets()
     {
-        char[]  cs = string.toCharArray();
-        byte[]  bs = new byte[cs.length];
+        return Arrays.clone(string);
+    }
 
-        for (int i = 0; i != cs.length; i++)
-        {
-            bs[i] = (byte)cs[i];
-        }
+    boolean isConstructed()
+    {
+        return false;
+    }
 
-        return bs; 
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(NUMERIC_STRING, this.getOctets());
+        out.writeEncoded(BERTags.NUMERIC_STRING, string);
     }
 
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERNumericString))
         {
@@ -142,7 +140,7 @@
 
         DERNumericString  s = (DERNumericString)o;
 
-        return this.getString().equals(s.getString());
+        return Arrays.areEqual(string, s.string);
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERObject.java b/src/main/java/org/bouncycastle/asn1/DERObject.java
deleted file mode 100644
index 42e2487..0000000
--- a/src/main/java/org/bouncycastle/asn1/DERObject.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.IOException;
-
-public abstract class DERObject
-    extends ASN1Encodable
-    implements DERTags
-{
-    public DERObject toASN1Object()
-    {
-        return this;
-    }
-    
-    public abstract int hashCode();
-    
-    public abstract boolean equals(Object o);
-    
-    abstract void encode(DEROutputStream out)
-        throws IOException;
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
index 8e579f7..02a0945 100644
--- a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -2,25 +2,33 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.math.BigInteger;
 
+import org.bouncycastle.util.Arrays;
+
 public class DERObjectIdentifier
-    extends ASN1Object
+    extends ASN1Primitive
 {
     String      identifier;
 
+    private     byte[] body;
+
     /**
      * return an OID from the passed in object
      *
      * @exception IllegalArgumentException if the object cannot be converted.
      */
-    public static DERObjectIdentifier getInstance(
+    public static ASN1ObjectIdentifier getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof DERObjectIdentifier)
+        if (obj == null || obj instanceof ASN1ObjectIdentifier)
         {
-            return (DERObjectIdentifier)obj;
+            return (ASN1ObjectIdentifier)obj;
+        }
+
+        if (obj instanceof DERObjectIdentifier)
+        {
+            return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -35,11 +43,11 @@
      * @exception IllegalArgumentException if the tagged object cannot
      *               be converted.
      */
-    public static DERObjectIdentifier getInstance(
+    public static ASN1ObjectIdentifier getInstance(
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERObjectIdentifier)
         {
@@ -47,10 +55,9 @@
         }
         else
         {
-            return new ASN1ObjectIdentifier(ASN1OctetString.getInstance(obj.getObject()).getOctets());
+            return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
         }
     }
-    
 
     DERObjectIdentifier(
         byte[]  bytes)
@@ -142,9 +149,8 @@
     }
 
     private void writeField(
-        OutputStream    out,
-        long            fieldValue)
-        throws IOException
+        ByteArrayOutputStream    out,
+        long                     fieldValue)
     {
         byte[] result = new byte[9];
         int pos = 8;
@@ -158,9 +164,8 @@
     }
 
     private void writeField(
-        OutputStream    out,
-        BigInteger      fieldValue)
-        throws IOException
+        ByteArrayOutputStream   out,
+        BigInteger              fieldValue)
     {
         int byteCount = (fieldValue.bitLength()+6)/7;
         if (byteCount == 0) 
@@ -177,41 +182,68 @@
                 tmpValue = tmpValue.shiftRight(7); 
             }
             tmp[byteCount-1] &= 0x7f;
-            out.write(tmp);
+            out.write(tmp, 0, tmp.length);
         }
-
     }
 
-    void encode(
-        DEROutputStream out)
-        throws IOException
+    private void doOutput(ByteArrayOutputStream aOut)
     {
         OIDTokenizer            tok = new OIDTokenizer(identifier);
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        DEROutputStream         dOut = new DEROutputStream(bOut);
 
-        writeField(bOut, 
+        writeField(aOut,
                     Integer.parseInt(tok.nextToken()) * 40
                     + Integer.parseInt(tok.nextToken()));
 
         while (tok.hasMoreTokens())
         {
             String token = tok.nextToken();
-            if (token.length() < 18) 
+            if (token.length() < 18)
             {
-                writeField(bOut, Long.parseLong(token));
+                writeField(aOut, Long.parseLong(token));
             }
             else
             {
-                writeField(bOut, new BigInteger(token));
+                writeField(aOut, new BigInteger(token));
             }
         }
+    }
 
-        dOut.close();
+    protected byte[] getBody()
+    {
+        if (body == null)
+        {
+            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
 
-        byte[]  bytes = bOut.toByteArray();
+            doOutput(bOut);
 
-        out.writeEncoded(OBJECT_IDENTIFIER, bytes);
+            body = bOut.toByteArray();
+        }
+
+        return body;
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBody().length;
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        byte[]                     enc = getBody();
+
+        out.write(BERTags.OBJECT_IDENTIFIER);
+        out.writeLength(enc.length);
+        out.write(enc);
     }
 
     public int hashCode()
@@ -220,7 +252,7 @@
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive  o)
     {
         if (!(o instanceof DERObjectIdentifier))
         {
@@ -277,4 +309,75 @@
 
         return periodAllowed;
     }
+
+    private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[255][];
+
+    static ASN1ObjectIdentifier fromOctetString(byte[] enc)
+    {
+        if (enc.length < 3)
+        {
+            return new ASN1ObjectIdentifier(enc);
+        }
+
+        int idx1 = enc[enc.length - 2] & 0xff;
+        ASN1ObjectIdentifier[] first = cache[idx1];
+
+        if (first == null)
+        {
+            first = cache[idx1] = new ASN1ObjectIdentifier[255];
+        }
+
+        int idx2 = enc[enc.length - 1] & 0xff;
+
+        ASN1ObjectIdentifier possibleMatch = first[idx2];
+
+        if (possibleMatch == null)
+        {
+            possibleMatch = first[idx2] = new ASN1ObjectIdentifier(enc);
+            return possibleMatch;
+        }
+
+        if (Arrays.areEqual(enc, possibleMatch.getBody()))
+        {
+            return possibleMatch;
+        }
+        else
+        {
+            idx1 = (idx1 + 1) % 256;
+            first = cache[idx1];
+            if (first == null)
+            {
+                first = cache[idx1] = new ASN1ObjectIdentifier[255];
+            }
+
+            possibleMatch = first[idx2];
+
+            if (possibleMatch == null)
+            {
+                possibleMatch = first[idx2] = new ASN1ObjectIdentifier(enc);
+                return possibleMatch;
+            }
+
+            if (Arrays.areEqual(enc, possibleMatch.getBody()))
+            {
+                return possibleMatch;
+            }
+
+            idx2 = (idx2 + 1) % 256;
+            possibleMatch = first[idx2];
+
+            if (possibleMatch == null)
+            {
+                possibleMatch = first[idx2] = new ASN1ObjectIdentifier(enc);
+                return possibleMatch;
+            }
+
+            if (Arrays.areEqual(enc, possibleMatch.getBody()))
+            {
+                return possibleMatch;
+            }
+        }
+
+        return new ASN1ObjectIdentifier(enc);
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DEROctetString.java b/src/main/java/org/bouncycastle/asn1/DEROctetString.java
index cadd60c..988186f 100644
--- a/src/main/java/org/bouncycastle/asn1/DEROctetString.java
+++ b/src/main/java/org/bouncycastle/asn1/DEROctetString.java
@@ -15,16 +15,27 @@
     }
 
     public DEROctetString(
-        DEREncodable  obj)
+        ASN1Encodable obj)
+        throws IOException
     {
-        super(obj);
+        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
     }
 
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(OCTET_STRING, string);
+        out.writeEncoded(BERTags.OCTET_STRING, string);
     }
 
     static void encode(
@@ -32,6 +43,6 @@
         byte[]          bytes)
         throws IOException
     {
-        derOut.writeEncoded(DERTags.OCTET_STRING, bytes);
+        derOut.writeEncoded(BERTags.OCTET_STRING, bytes);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
index 2318f5c..e6e2068 100644
--- a/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
@@ -19,13 +19,13 @@
         return stream;
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
         return new DEROctetString(stream.toByteArray());
     }
     
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DEROutputStream.java b/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
index b78f7ca..8b18c3d 100644
--- a/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
@@ -1,11 +1,13 @@
 package org.bouncycastle.asn1;
 
-import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
+/**
+ * Stream that outputs encoding based on distinguished encoding rules.
+ */
 public class DEROutputStream
-    extends FilterOutputStream implements DERTags
+    extends ASN1OutputStream
 {
     public DEROutputStream(
         OutputStream    os)
@@ -13,122 +15,27 @@
         super(os);
     }
 
-    private void writeLength(
-        int length)
-        throws IOException
-    {
-        if (length > 127)
-        {
-            int size = 1;
-            int val = length;
-
-            while ((val >>>= 8) != 0)
-            {
-                size++;
-            }
-
-            write((byte)(size | 0x80));
-
-            for (int i = (size - 1) * 8; i >= 0; i -= 8)
-            {
-                write((byte)(length >> i));
-            }
-        }
-        else
-        {
-            write((byte)length);
-        }
-    }
-
-    void writeEncoded(
-        int     tag,
-        byte[]  bytes)
-        throws IOException
-    {
-        write(tag);
-        writeLength(bytes.length);
-        write(bytes);
-    }
-
-    void writeTag(int flags, int tagNo)
-        throws IOException
-    {
-        if (tagNo < 31)
-        {
-            write(flags | tagNo);
-        }
-        else
-        {
-            write(flags | 0x1f);
-            if (tagNo < 128)
-            {
-                write(tagNo);
-            }
-            else
-            {
-                byte[] stack = new byte[5];
-                int pos = stack.length;
-
-                stack[--pos] = (byte)(tagNo & 0x7F);
-
-                do
-                {
-                    tagNo >>= 7;
-                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
-                }
-                while (tagNo > 127);
-
-                write(stack, pos, stack.length - pos);
-            }
-        }
-    }
-
-    void writeEncoded(int flags, int tagNo, byte[] bytes)
-        throws IOException
-    {
-        writeTag(flags, tagNo);
-        writeLength(bytes.length);
-        write(bytes);
-    }
-
-    protected void writeNull()
-        throws IOException
-    {
-        write(NULL);
-        write(0x00);
-    }
-
-    public void write(byte[] buf)
-        throws IOException
-    {
-        out.write(buf, 0, buf.length);
-    }
-
-    public void write(byte[] buf, int offSet, int len)
-        throws IOException
-    {
-        out.write(buf, offSet, len);
-    }
-
     public void writeObject(
-        Object    obj)
+        ASN1Encodable obj)
         throws IOException
     {
-        if (obj == null)
+        if (obj != null)
         {
-            writeNull();
+            obj.toASN1Primitive().toDERObject().encode(this);
         }
-        else if (obj instanceof DERObject)
+        else
         {
-            ((DERObject)obj).encode(this);
+            throw new IOException("null object detected");
         }
-        else if (obj instanceof DEREncodable)
-        {
-            ((DEREncodable)obj).getDERObject().encode(this);
-        }
-        else 
-        {
-            throw new IOException("object not DEREncodable");
-        }
+    }
+
+    ASN1OutputStream getDERSubStream()
+    {
+        return this;
+    }
+
+    ASN1OutputStream getDLSubStream()
+    {
+        return this;
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
index 2f84c1c..6c56e83 100644
--- a/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
@@ -2,15 +2,18 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * DER PrintableString object.
  */
 public class DERPrintableString
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
     // BEGIN android-changed
-    private final String string;
+    private final byte[]  string;
     // END android-changed
 
     /**
@@ -42,7 +45,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERPrintableString)
         {
@@ -57,19 +60,10 @@
     /**
      * basic constructor - byte encoded string.
      */
-    public DERPrintableString(
+    DERPrintableString(
         byte[]   string)
     {
-        char[]  cs = new char[string.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(string[i] & 0xff);
-        }
-
-        // BEGIN android-changed
-        this.string = new String(cs).intern();
-        // END android-changed
+        this.string = string;
     }
 
     /**
@@ -98,43 +92,43 @@
             throw new IllegalArgumentException("string contains illegal characters");
         }
 
-        // BEGIN android-changed
-        this.string = string.intern();
-        // END android-changed
+        this.string = Strings.toByteArray(string);
     }
 
     public String getString()
     {
-        return string;
+        return Strings.fromByteArray(string);
     }
 
     public byte[] getOctets()
     {
-        char[]  cs = string.toCharArray();
-        byte[]  bs = new byte[cs.length];
+        return Arrays.clone(string);
+    }
 
-        for (int i = 0; i != cs.length; i++)
-        {
-            bs[i] = (byte)cs[i];
-        }
+    boolean isConstructed()
+    {
+        return false;
+    }
 
-        return bs; 
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(PRINTABLE_STRING, this.getOctets());
+        out.writeEncoded(BERTags.PRINTABLE_STRING, string);
     }
 
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERPrintableString))
         {
@@ -143,12 +137,12 @@
 
         DERPrintableString  s = (DERPrintableString)o;
 
-        return this.getString().equals(s.getString());
+        return Arrays.areEqual(string, s.string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERSequence.java b/src/main/java/org/bouncycastle/asn1/DERSequence.java
index bb7f7fb..ad48a83 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSequence.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSequence.java
@@ -1,12 +1,13 @@
 package org.bouncycastle.asn1;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Enumeration;
 
 public class DERSequence
     extends ASN1Sequence
 {
+    private int bodyLength = -1;
+
     /**
      * create an empty sequence
      */
@@ -18,63 +19,80 @@
      * create a sequence containing one object
      */
     public DERSequence(
-        DEREncodable    obj)
+        ASN1Encodable obj)
     {
-        this.addObject(obj);
+        super(obj);
     }
 
     /**
      * create a sequence containing a vector of objects.
      */
     public DERSequence(
-        ASN1EncodableVector   v)
+        ASN1EncodableVector v)
     {
-        for (int i = 0; i != v.size(); i++)
-        {
-            this.addObject(v.get(i));
-        }
+        super(v);
     }
 
     /**
      * create a sequence containing an array of objects.
      */
     public DERSequence(
-        ASN1Encodable[]   a)
+        ASN1Encodable[]   array)
     {
-        for (int i = 0; i != a.length; i++)
-        {
-            this.addObject(a[i]);
-        }
+        super(array);
     }
-    
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object    obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
     /*
      * A note on the implementation:
      * <p>
      * As DER requires the constructed, definite-length model to
      * be used for structured types, this varies slightly from the
-     * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+     * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
      * we also have to specify CONSTRUCTED, and the objects length.
      */
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        // TODO Intermediate buffer could be avoided if we could calculate expected length
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        DEROutputStream         dOut = new DEROutputStream(bOut);
-        Enumeration             e = this.getObjects();
+        ASN1OutputStream        dOut = out.getDERSubStream();
+        int                     length = getBodyLength();
 
-        while (e.hasMoreElements())
+        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
         {
             Object    obj = e.nextElement();
 
-            dOut.writeObject(obj);
+            dOut.writeObject((ASN1Encodable)obj);
         }
-
-        dOut.close();
-
-        byte[]  bytes = bOut.toByteArray();
-
-        out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java b/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
index b91dfa0..376c1fd 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
@@ -12,19 +12,19 @@
         this._parser = parser;
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         return _parser.readObject();
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
          return new DERSequence(_parser.readVector());
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERSet.java b/src/main/java/org/bouncycastle/asn1/DERSet.java
index c4acc82..c1faf84 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSet.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSet.java
@@ -1,6 +1,5 @@
 package org.bouncycastle.asn1;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Enumeration;
 
@@ -10,6 +9,8 @@
 public class DERSet
     extends ASN1Set
 {
+    private int bodyLength = -1;
+
     /**
      * create an empty set
      */
@@ -21,18 +22,18 @@
      * @param obj - a single object that makes up the set.
      */
     public DERSet(
-        DEREncodable   obj)
+        ASN1Encodable obj)
     {
-        this.addObject(obj);
+        super(obj);
     }
 
     /**
      * @param v - a vector of objects making up the set.
      */
     public DERSet(
-        ASN1EncodableVector   v)
+        ASN1EncodableVector v)
     {
-        this(v, true);
+        super(v, true);
     }
     
     /**
@@ -41,30 +42,42 @@
     public DERSet(
         ASN1Encodable[]   a)
     {
-        for (int i = 0; i != a.length; i++)
-        {
-            this.addObject(a[i]);
-        }
-        
-        this.sort();
+        super(a, true);
     }
-    
-    /**
-     * @param v - a vector of objects making up the set.
-     */
+
     DERSet(
-        ASN1EncodableVector  v,
-        boolean              needsSorting)
+        ASN1EncodableVector v,
+        boolean                  doSort)
     {
-        for (int i = 0; i != v.size(); i++)
+        super(v, doSort);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
         {
-            this.addObject(v.get(i));
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object    obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
+            }
+
+            bodyLength = length;
         }
 
-        if (needsSorting)
-        {
-            this.sort();
-        }
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
     }
 
     /*
@@ -72,29 +85,24 @@
      * <p>
      * As DER requires the constructed, definite-length model to
      * be used for structured types, this varies slightly from the
-     * ASN.1 descriptions given. Rather than just outputing SET,
+     * ASN.1 descriptions given. Rather than just outputting SET,
      * we also have to specify CONSTRUCTED, and the objects length.
      */
     void encode(
-        DEROutputStream out)
+        ASN1OutputStream out)
         throws IOException
     {
-        // TODO Intermediate buffer could be avoided if we could calculate expected length
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        DEROutputStream         dOut = new DEROutputStream(bOut);
-        Enumeration             e = this.getObjects();
+        ASN1OutputStream        dOut = out.getDERSubStream();
+        int                     length = getBodyLength();
 
-        while (e.hasMoreElements())
+        out.write(BERTags.SET | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
         {
             Object    obj = e.nextElement();
 
-            dOut.writeObject(obj);
+            dOut.writeObject((ASN1Encodable)obj);
         }
-
-        dOut.close();
-
-        byte[]  bytes = bOut.toByteArray();
-
-        out.writeEncoded(SET | CONSTRUCTED, bytes);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERSetParser.java b/src/main/java/org/bouncycastle/asn1/DERSetParser.java
index 44ddb80..17702fa 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSetParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSetParser.java
@@ -12,19 +12,19 @@
         this._parser = parser;
     }
 
-    public DEREncodable readObject()
+    public ASN1Encodable readObject()
         throws IOException
     {
         return _parser.readObject();
     }
 
-    public DERObject getLoadedObject()
+    public ASN1Primitive getLoadedObject()
         throws IOException
     {
         return new DERSet(_parser.readVector(), false);
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive toASN1Primitive()
     {
         try
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERString.java b/src/main/java/org/bouncycastle/asn1/DERString.java
deleted file mode 100644
index 37dc905..0000000
--- a/src/main/java/org/bouncycastle/asn1/DERString.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.bouncycastle.asn1;
-
-/**
- * basic interface for DER string objects.
- */
-public interface DERString
-    extends ASN1String
-{
-
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DERT61String.java b/src/main/java/org/bouncycastle/asn1/DERT61String.java
index 519a950..ee2979b 100644
--- a/src/main/java/org/bouncycastle/asn1/DERT61String.java
+++ b/src/main/java/org/bouncycastle/asn1/DERT61String.java
@@ -2,14 +2,17 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * DER T61String (also the teletex string)
  */
 public class DERT61String
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    String  string;
+    private byte[] string;
 
     /**
      * return a T61 string from the passed in object.
@@ -40,9 +43,9 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
-        if (explicit)
+        if (explicit || o instanceof DERT61String)
         {
             return getInstance(o);
         }
@@ -55,17 +58,10 @@
     /**
      * basic constructor - with bytes.
      */
-    public DERT61String(
+    DERT61String(
         byte[]   string)
     {
-        char[]  cs = new char[string.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(string[i] & 0xff);
-        }
-
-        this.string = new String(cs);
+        this.string = string;
     }
 
     /**
@@ -74,52 +70,54 @@
     public DERT61String(
         String   string)
     {
-        this.string = string;
+        this.string = Strings.toByteArray(string);
     }
 
     public String getString()
     {
-        return string;
+        return Strings.fromByteArray(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(T61_STRING, this.getOctets());
+        out.writeEncoded(BERTags.T61_STRING, string);
     }
     
     public byte[] getOctets()
     {
-        char[]  cs = string.toCharArray();
-        byte[]  bs = new byte[cs.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            bs[i] = (byte)cs[i];
-        }
-
-        return bs; 
+        return Arrays.clone(string);
     }
 
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERT61String))
         {
             return false;
         }
 
-        return this.getString().equals(((DERT61String)o).getString());
+        return Arrays.areEqual(string, ((DERT61String)o).string);
     }
     
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java b/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
index a1d3687..a87a0dc 100644
--- a/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
+++ b/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
@@ -13,50 +13,83 @@
     private static final byte[] ZERO_BYTES = new byte[0];
 
     /**
-     * @param tagNo the tag number for this object.
-     * @param obj the tagged object.
-     */
-    public DERTaggedObject(
-        int             tagNo,
-        DEREncodable    obj)
-    {
-        super(tagNo, obj);
-    }
-
-    /**
      * @param explicit true if an explicitly tagged object.
      * @param tagNo the tag number for this object.
      * @param obj the tagged object.
      */
     public DERTaggedObject(
-        boolean         explicit,
-        int             tagNo,
-        DEREncodable    obj)
+        boolean       explicit,
+        int           tagNo,
+        ASN1Encodable obj)
     {
         super(explicit, tagNo, obj);
     }
 
-    /**
-     * create an implicitly tagged object that contains a zero
-     * length sequence.
-     */
-    public DERTaggedObject(
-        int             tagNo)
+    public DERTaggedObject(int tagNo, ASN1Encodable encodable)
     {
-        super(false, tagNo, new DERSequence());
+        super(true, tagNo, encodable);
     }
 
-    void encode(
-        DEROutputStream  out)
+    boolean isConstructed()
+    {
+        if (!empty)
+        {
+            if (explicit)
+            {
+                return true;
+            }
+            else
+            {
+                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+                return primitive.isConstructed();
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    int encodedLength()
         throws IOException
     {
         if (!empty)
         {
-            byte[] bytes = obj.getDERObject().getEncoded(DER);
+            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+            int length = primitive.encodedLength();
 
             if (explicit)
             {
-                out.writeEncoded(CONSTRUCTED | TAGGED, tagNo, bytes);
+                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+            }
+            else
+            {
+                // header length already in calculation
+                length = length - 1;
+
+                return StreamUtil.calculateTagLength(tagNo) + length;
+            }
+        }
+        else
+        {
+            return StreamUtil.calculateTagLength(tagNo) + 1;
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+            if (explicit)
+            {
+                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+                out.writeLength(primitive.encodedLength());
+                out.writeObject(primitive);
             }
             else
             {
@@ -64,22 +97,22 @@
                 // need to mark constructed types...
                 //
                 int flags;
-                if ((bytes[0] & CONSTRUCTED) != 0)
+                if (primitive.isConstructed())
                 {
-                    flags = CONSTRUCTED | TAGGED;
+                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
                 }
                 else
                 {
-                    flags = TAGGED;
+                    flags = BERTags.TAGGED;
                 }
 
                 out.writeTag(flags, tagNo);
-                out.write(bytes, 1, bytes.length - 1);
+                out.writeImplicitObject(primitive);
             }
         }
         else
         {
-            out.writeEncoded(CONSTRUCTED | TAGGED, tagNo, ZERO_BYTES);
+            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
         }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERTags.java b/src/main/java/org/bouncycastle/asn1/DERTags.java
index ef441ef..83fd7fd 100644
--- a/src/main/java/org/bouncycastle/asn1/DERTags.java
+++ b/src/main/java/org/bouncycastle/asn1/DERTags.java
@@ -1,36 +1,9 @@
 package org.bouncycastle.asn1;
 
+/**
+ * @deprecated use BERTags
+ */
 public interface DERTags
+    extends BERTags
 {
-    public static final int BOOLEAN             = 0x01;
-    public static final int INTEGER             = 0x02;
-    public static final int BIT_STRING          = 0x03;
-    public static final int OCTET_STRING        = 0x04;
-    public static final int NULL                = 0x05;
-    public static final int OBJECT_IDENTIFIER   = 0x06;
-    public static final int EXTERNAL            = 0x08;
-    public static final int ENUMERATED          = 0x0a;
-    public static final int SEQUENCE            = 0x10;
-    public static final int SEQUENCE_OF         = 0x10; // for completeness
-    public static final int SET                 = 0x11;
-    public static final int SET_OF              = 0x11; // for completeness
-
-
-    public static final int NUMERIC_STRING      = 0x12;
-    public static final int PRINTABLE_STRING    = 0x13;
-    public static final int T61_STRING          = 0x14;
-    public static final int VIDEOTEX_STRING     = 0x15;
-    public static final int IA5_STRING          = 0x16;
-    public static final int UTC_TIME            = 0x17;
-    public static final int GENERALIZED_TIME    = 0x18;
-    public static final int GRAPHIC_STRING      = 0x19;
-    public static final int VISIBLE_STRING      = 0x1a;
-    public static final int GENERAL_STRING      = 0x1b;
-    public static final int UNIVERSAL_STRING    = 0x1c;
-    public static final int BMP_STRING          = 0x1e;
-    public static final int UTF8_STRING         = 0x0c;
-    
-    public static final int CONSTRUCTED         = 0x20;
-    public static final int APPLICATION         = 0x40;
-    public static final int TAGGED              = 0x80;
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERUTCTime.java b/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
index f183d72..a5bdef1 100644
--- a/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
+++ b/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
@@ -6,25 +6,33 @@
 import java.util.Date;
 import java.util.SimpleTimeZone;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * UTC time object.
  */
 public class DERUTCTime
-    extends ASN1Object
+    extends ASN1Primitive
 {
-    String      time;
+    private byte[]      time;
 
     /**
      * return an UTC Time from the passed in object.
      *
      * @exception IllegalArgumentException if the object cannot be converted.
      */
-    public static DERUTCTime getInstance(
+    public static ASN1UTCTime getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof DERUTCTime)
+        if (obj == null || obj instanceof ASN1UTCTime)
         {
-            return (DERUTCTime)obj;
+            return (ASN1UTCTime)obj;
+        }
+
+        if (obj instanceof DERUTCTime)
+        {
+            return new ASN1UTCTime(((DERUTCTime)obj).time);
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -39,19 +47,19 @@
      * @exception IllegalArgumentException if the tagged object cannot
      *               be converted.
      */
-    public static DERUTCTime getInstance(
+    public static ASN1UTCTime getInstance(
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Object o = obj.getObject();
 
-        if (explicit || o instanceof DERUTCTime)
+        if (explicit || o instanceof ASN1UTCTime)
         {
             return getInstance(o);
         }
         else
         {
-            return new DERUTCTime(((ASN1OctetString)o).getOctets());
+            return new ASN1UTCTime(((ASN1OctetString)o).getOctets());
         }
     }
     
@@ -68,7 +76,7 @@
     public DERUTCTime(
         String  time)
     {
-        this.time = time;
+        this.time = Strings.toByteArray(time);
         try
         {
             this.getDate();
@@ -89,23 +97,13 @@
 
         dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
 
-        this.time = dateF.format(time);
+        this.time = Strings.toByteArray(dateF.format(time));
     }
 
     DERUTCTime(
-        byte[]  bytes)
+        byte[]  time)
     {
-        //
-        // explicitly convert to characters
-        //
-        char[]  dateC = new char[bytes.length];
-
-        for (int i = 0; i != dateC.length; i++)
-        {
-            dateC[i] = (char)(bytes[i] & 0xff);
-        }
-
-        this.time = new String(dateC);
+        this.time = time;
     }
 
     /**
@@ -158,30 +156,32 @@
      */
     public String getTime()
     {
+        String stime = Strings.fromByteArray(time);
+
         //
         // standardise the format.
         //
-        if (time.indexOf('-') < 0 && time.indexOf('+') < 0)
+        if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)
         {
-            if (time.length() == 11)
+            if (stime.length() == 11)
             {
-                return time.substring(0, 10) + "00GMT+00:00";
+                return stime.substring(0, 10) + "00GMT+00:00";
             }
             else
             {
-                return time.substring(0, 12) + "GMT+00:00";
+                return stime.substring(0, 12) + "GMT+00:00";
             }
         }
         else
         {
-            int index = time.indexOf('-');
+            int index = stime.indexOf('-');
             if (index < 0)
             {
-                index = time.indexOf('+');
+                index = stime.indexOf('+');
             }
-            String d = time;
+            String d = stime;
 
-            if (index == time.length() - 3)
+            if (index == stime.length() - 3)
             {
                 d += "00";
             }
@@ -215,44 +215,52 @@
         }
     }
 
-    private byte[] getOctets()
+    boolean isConstructed()
     {
-        char[]  cs = time.toCharArray();
-        byte[]  bs = new byte[cs.length];
+        return false;
+    }
 
-        for (int i = 0; i != cs.length; i++)
-        {
-            bs[i] = (byte)cs[i];
-        }
+    int encodedLength()
+    {
+        int length = time.length;
 
-        return bs;
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream  out)
         throws IOException
     {
-        out.writeEncoded(UTC_TIME, this.getOctets());
+        out.write(BERTags.UTC_TIME);
+
+        int length = time.length;
+
+        out.writeLength(length);
+
+        for (int i = 0; i != length; i++)
+        {
+            out.write((byte)time[i]);
+        }
     }
     
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERUTCTime))
         {
             return false;
         }
 
-        return time.equals(((DERUTCTime)o).time);
+        return Arrays.areEqual(time, ((DERUTCTime)o).time);
     }
     
     public int hashCode()
     {
-        return time.hashCode();
+        return Arrays.hashCode(time);
     }
 
     public String toString() 
     {
-      return time;
+      return Strings.fromByteArray(time);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERUTF8String.java b/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
index 06d6fe9..f46f558 100644
--- a/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
+++ b/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
@@ -2,16 +2,17 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.Strings;
 
 /**
  * DER UTF8String object.
  */
 public class DERUTF8String
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    String string;
+    private byte[]  string;
 
     /**
      * return an UTF8 string from the passed in object.
@@ -45,7 +46,7 @@
         ASN1TaggedObject obj,
         boolean explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERUTF8String)
         {
@@ -60,16 +61,9 @@
     /**
      * basic constructor - byte encoded string.
      */
-    public DERUTF8String(byte[] string)
+    DERUTF8String(byte[] string)
     {
-        try
-        {
-            this.string = Strings.fromUTF8ByteArray(string);
-        }
-        catch (ArrayIndexOutOfBoundsException e)
-        {
-            throw new IllegalArgumentException("UTF8 encoding invalid");
-        }
+        this.string = string;
     }
 
     /**
@@ -77,25 +71,25 @@
      */
     public DERUTF8String(String string)
     {
-        this.string = string;
+        this.string = Strings.toUTF8ByteArray(string);
     }
 
     public String getString()
     {
-        return string;
+        return Strings.fromUTF8ByteArray(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 
-    boolean asn1Equals(DERObject o)
+    boolean asn1Equals(ASN1Primitive o)
     {
         if (!(o instanceof DERUTF8String))
         {
@@ -104,12 +98,23 @@
 
         DERUTF8String s = (DERUTF8String)o;
 
-        return this.getString().equals(s.getString());
+        return Arrays.areEqual(string, s.string);
     }
 
-    void encode(DEROutputStream out)
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
         throws IOException
     {
-        out.writeEncoded(UTF8_STRING, Strings.toUTF8ByteArray(string));
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.UTF8_STRING, string);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
index 6e54934..4fe82f0 100644
--- a/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
@@ -3,12 +3,14 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+
 /**
  * DER UniversalString object.
  */
 public class DERUniversalString
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
     private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
     private byte[] string;
@@ -42,7 +44,7 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        DERObject o = obj.getObject();
+        ASN1Primitive o = obj.getObject();
 
         if (explicit || o instanceof DERUniversalString)
         {
@@ -99,26 +101,36 @@
         return string;
     }
 
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(UNIVERSAL_STRING, this.getOctets());
+        out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets());
     }
     
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERUniversalString))
         {
             return false;
         }
 
-        return this.getString().equals(((DERUniversalString)o).getString());
+        return Arrays.areEqual(string, ((DERUniversalString)o).string);
     }
     
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERUnknownTag.java b/src/main/java/org/bouncycastle/asn1/DERUnknownTag.java
deleted file mode 100644
index 1feed40..0000000
--- a/src/main/java/org/bouncycastle/asn1/DERUnknownTag.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.IOException;
-
-import org.bouncycastle.util.Arrays;
-
-/**
- * We insert one of these when we find a tag we don't recognise.
- */
-public class DERUnknownTag
-    extends DERObject
-{
-    private boolean   isConstructed;
-    private int       tag;
-    private byte[]    data;
-
-    /**
-     * @param tag the tag value.
-     * @param data the contents octets.
-     */
-    public DERUnknownTag(
-        int     tag,
-        byte[]  data)
-    {
-        this(false, tag, data);
-    }
-
-    public DERUnknownTag(
-        boolean isConstructed,
-        int     tag,
-        byte[]  data)
-    {
-        this.isConstructed = isConstructed;
-        this.tag = tag;
-        this.data = data;
-    }
-
-    public boolean isConstructed()
-    {
-        return isConstructed;
-    }
-
-    public int getTag()
-    {
-        return tag;
-    }
-
-    public byte[] getData()
-    {
-        return data;
-    }
-
-    void encode(
-        DEROutputStream  out)
-        throws IOException
-    {
-        out.writeEncoded(isConstructed ? DERTags.CONSTRUCTED : 0, tag, data);
-    }
-    
-    public boolean equals(
-        Object o)
-    {
-        if (!(o instanceof DERUnknownTag))
-        {
-            return false;
-        }
-        
-        DERUnknownTag other = (DERUnknownTag)o;
-
-        return isConstructed == other.isConstructed
-            && tag == other.tag
-            && Arrays.areEqual(data, other.data);
-    }
-    
-    public int hashCode()
-    {
-        return (isConstructed ? ~0 : 0) ^ tag ^ Arrays.hashCode(data);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DERVisibleString.java b/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
index 9d0c991..1c385b7 100644
--- a/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
@@ -2,14 +2,17 @@
 
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 /**
  * DER VisibleString object.
  */
 public class DERVisibleString
-    extends ASN1Object
-    implements DERString
+    extends ASN1Primitive
+    implements ASN1String
 {
-    String  string;
+    private byte[]  string;
 
     /**
      * return a Visible String from the passed in object.
@@ -24,16 +27,6 @@
             return (DERVisibleString)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERVisibleString(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -50,23 +43,25 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERVisibleString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERVisibleString(ASN1OctetString.getInstance(o).getOctets());
+        }
     }
 
     /**
      * basic constructor - byte encoded string.
      */
-    public DERVisibleString(
+    DERVisibleString(
         byte[]   string)
     {
-        char[]  cs = new char[string.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(string[i] & 0xff);
-        }
-
-        this.string = new String(cs);
+        this.string = string;
     }
 
     /**
@@ -75,52 +70,54 @@
     public DERVisibleString(
         String   string)
     {
-        this.string = string;
+        this.string = Strings.toByteArray(string);
     }
 
     public String getString()
     {
-        return string;
+        return Strings.fromByteArray(string);
     }
 
     public String toString()
     {
-        return string;
+        return getString();
     }
 
     public byte[] getOctets()
     {
-        char[]  cs = string.toCharArray();
-        byte[]  bs = new byte[cs.length];
+        return Arrays.clone(string);
+    }
 
-        for (int i = 0; i != cs.length; i++)
-        {
-            bs[i] = (byte)cs[i];
-        }
+    boolean isConstructed()
+    {
+        return false;
+    }
 
-        return bs;
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
     }
 
     void encode(
-        DEROutputStream  out)
+        ASN1OutputStream out)
         throws IOException
     {
-        out.writeEncoded(VISIBLE_STRING, this.getOctets());
+        out.writeEncoded(BERTags.VISIBLE_STRING, this.string);
     }
     
     boolean asn1Equals(
-        DERObject  o)
+        ASN1Primitive o)
     {
         if (!(o instanceof DERVisibleString))
         {
             return false;
         }
 
-        return this.getString().equals(((DERVisibleString)o).getString());
+        return Arrays.areEqual(string, ((DERVisibleString)o).string);
     }
     
     public int hashCode()
     {
-        return this.getString().hashCode();
+        return Arrays.hashCode(string);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DLOutputStream.java b/src/main/java/org/bouncycastle/asn1/DLOutputStream.java
new file mode 100644
index 0000000..68c0ed6
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/DLOutputStream.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that outputs encoding based on definite length.
+ */
+public class DLOutputStream
+    extends ASN1OutputStream
+{
+    public DLOutputStream(
+        OutputStream os)
+    {
+        super(os);
+    }
+
+    public void writeObject(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.toASN1Primitive().toDLObject().encode(this);
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/DLSequence.java b/src/main/java/org/bouncycastle/asn1/DLSequence.java
new file mode 100644
index 0000000..bb8ec4e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/DLSequence.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class DLSequence
+    extends ASN1Sequence
+{
+    private int bodyLength = -1;
+
+    /**
+     * create an empty sequence
+     */
+    public DLSequence()
+    {
+    }
+
+    /**
+     * create a sequence containing one object
+     */
+    public DLSequence(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    public DLSequence(
+        ASN1EncodableVector v)
+    {
+        super(v);
+    }
+
+    /**
+     * create a sequence containing an array of objects.
+     */
+    public DLSequence(
+        ASN1Encodable[] array)
+    {
+        super(array);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object    obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int    length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DL requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        ASN1OutputStream       dOut = out.getDLSubStream();
+        int                    length = getBodyLength();
+
+        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject((ASN1Encodable)obj);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/DLSet.java b/src/main/java/org/bouncycastle/asn1/DLSet.java
new file mode 100644
index 0000000..755754b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/DLSet.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * A DER encoded set object
+ */
+public class DLSet
+    extends ASN1Set
+{
+    private int bodyLength = -1;
+
+    /**
+     * create an empty set
+     */
+    public DLSet()
+    {
+    }
+
+    /**
+     * @param obj - a single object that makes up the set.
+     */
+    public DLSet(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    public DLSet(
+        ASN1EncodableVector v)
+    {
+        super(v, false);
+    }
+
+    /**
+     * create a set from an array of objects.
+     */
+    public DLSet(
+        ASN1Encodable[] a)
+    {
+        super(a, false);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object    obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int                     length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DL requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputting SET,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        ASN1OutputStream        dOut = out.getDLSubStream();
+        int                     length = getBodyLength();
+
+        out.write(BERTags.SET | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject((ASN1Encodable)obj);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java b/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java
new file mode 100644
index 0000000..4a245df
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Definite Length TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+public class DLTaggedObject
+    extends ASN1TaggedObject
+{
+    private static final byte[] ZERO_BYTES = new byte[0];
+
+    /**
+     * @param explicit true if an explicitly tagged object.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public DLTaggedObject(
+        boolean explicit,
+        int tagNo,
+        ASN1Encodable obj)
+    {
+        super(explicit, tagNo, obj);
+    }
+
+    boolean isConstructed()
+    {
+        if (!empty)
+        {
+            if (explicit)
+            {
+                return true;
+            }
+            else
+            {
+                ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
+
+                return primitive.isConstructed();
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (!empty)
+        {
+            int length = obj.toASN1Primitive().toDLObject().encodedLength();
+
+            if (explicit)
+            {
+                return  StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+            }
+            else
+            {
+                // header length already in calculation
+                length = length - 1;
+
+                return StreamUtil.calculateTagLength(tagNo) + length;
+            }
+        }
+        else
+        {
+            return StreamUtil.calculateTagLength(tagNo) + 1;
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
+
+            if (explicit)
+            {
+                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+                out.writeLength(primitive.encodedLength());
+                out.writeObject(primitive);
+            }
+            else
+            {
+                //
+                // need to mark constructed types...
+                //
+                int flags;
+                if (primitive.isConstructed())
+                {
+                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
+                }
+                else
+                {
+                    flags = BERTags.TAGGED;
+                }
+
+                out.writeTag(flags, tagNo);
+                out.writeImplicitObject(primitive);
+            }
+        }
+        else
+        {
+            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
index 3785174..3f6ce22 100644
--- a/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
@@ -17,6 +17,7 @@
     DefiniteLengthInputStream(
         InputStream in,
         int         length)
+        throws IOException
     {
         super(in, length);
 
diff --git a/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java b/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
index 981ee1b..a4b1492 100644
--- a/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
+++ b/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
@@ -4,6 +4,6 @@
 
 public interface InMemoryRepresentable
 {
-    DERObject getLoadedObject()
+    ASN1Primitive getLoadedObject()
         throws IOException;
 }
diff --git a/src/main/java/org/bouncycastle/asn1/LazyDERConstructionEnumeration.java b/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java
similarity index 88%
rename from src/main/java/org/bouncycastle/asn1/LazyDERConstructionEnumeration.java
rename to src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java
index c5dfbc1..31d988d 100644
--- a/src/main/java/org/bouncycastle/asn1/LazyDERConstructionEnumeration.java
+++ b/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java
@@ -1,15 +1,15 @@
 package org.bouncycastle.asn1;
 
-import java.util.Enumeration;
 import java.io.IOException;
+import java.util.Enumeration;
 
-class LazyDERConstructionEnumeration
+class LazyConstructionEnumeration
     implements Enumeration
 {
     private ASN1InputStream aIn;
     private Object          nextObj;
 
-    public LazyDERConstructionEnumeration(byte[] encoded)
+    public LazyConstructionEnumeration(byte[] encoded)
     {
         aIn = new ASN1InputStream(encoded, true);
         nextObj = readObject();
diff --git a/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java b/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java
deleted file mode 100644
index 91074a6..0000000
--- a/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.IOException;
-import java.util.Enumeration;
-
-public class LazyDERSequence
-    extends DERSequence
-{
-    private byte[] encoded;
-    private boolean parsed = false;
-    private int size = -1;
-
-    LazyDERSequence(
-        byte[] encoded)
-        throws IOException
-    {
-        this.encoded = encoded;
-    }
-
-    private void parse()
-    {
-        Enumeration en = new LazyDERConstructionEnumeration(encoded);
-
-        while (en.hasMoreElements())
-        {
-            addObject((DEREncodable)en.nextElement());
-        }
-
-        parsed = true;
-    }
-
-    public synchronized DEREncodable getObjectAt(int index)
-    {
-        if (!parsed)
-        {
-            parse();
-        }
-
-        return super.getObjectAt(index);
-    }
-
-    public synchronized Enumeration getObjects()
-    {
-        if (parsed)
-        {
-            return super.getObjects();
-        }
-
-        return new LazyDERConstructionEnumeration(encoded);
-    }
-
-    public int size()
-    {
-        if (size < 0)
-        {
-            Enumeration en = new LazyDERConstructionEnumeration(encoded);
-
-            size = 0;
-            while (en.hasMoreElements())
-            {
-                en.nextElement();
-                size++;
-            }
-        }
-
-        return size;
-    }
-    
-    void encode(
-        DEROutputStream out)
-        throws IOException
-    {
-        out.writeEncoded(SEQUENCE | CONSTRUCTED, encoded);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java b/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java
new file mode 100644
index 0000000..c7342ad
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java
@@ -0,0 +1,109 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Note: this class is for processing DER/DL encoded sequences only.
+ */
+class LazyEncodedSequence
+    extends ASN1Sequence
+{
+    private byte[] encoded;
+
+    LazyEncodedSequence(
+        byte[] encoded)
+        throws IOException
+    {
+        this.encoded = encoded;
+    }
+
+    private void parse()
+    {
+        Enumeration en = new LazyConstructionEnumeration(encoded);
+
+        while (en.hasMoreElements())
+        {
+            seq.addElement(en.nextElement());
+        }
+
+        encoded = null;
+    }
+
+    public synchronized ASN1Encodable getObjectAt(int index)
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.getObjectAt(index);
+    }
+
+    public synchronized Enumeration getObjects()
+    {
+        if (encoded == null)
+        {
+            return super.getObjects();
+        }
+
+        return new LazyConstructionEnumeration(encoded);
+    }
+
+    public synchronized int size()
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.size();
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.toDERObject();
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.toDLObject();
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (encoded != null)
+        {
+            return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length;
+        }
+        else
+        {
+            return super.toDLObject().encodedLength();
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        if (encoded != null)
+        {
+            out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded);
+        }
+        else
+        {
+            super.toDLObject().encode(out);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/StreamUtil.java b/src/main/java/org/bouncycastle/asn1/StreamUtil.java
new file mode 100644
index 0000000..0a3c4aa
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/StreamUtil.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+class StreamUtil
+{
+    private static final long  MAX_MEMORY = Runtime.getRuntime().maxMemory();
+
+    /**
+     * Find out possible longest length...
+     *
+     * @param in input stream of interest
+     * @return length calculation or MAX_VALUE.
+     */
+    static int findLimit(InputStream in)
+    {
+        if (in instanceof LimitedInputStream)
+        {
+            return ((LimitedInputStream)in).getRemaining();
+        }
+        else if (in instanceof ASN1InputStream)
+        {
+            return ((ASN1InputStream)in).getLimit();
+        }
+        else if (in instanceof ByteArrayInputStream)
+        {
+            return ((ByteArrayInputStream)in).available();
+        }
+        else if (in instanceof FileInputStream)
+        {
+            try
+            {
+                long  size = ((FileInputStream)in).getChannel().size();
+
+                if (size < Integer.MAX_VALUE)
+                {
+                    return (int)size;
+                }
+            }
+            catch (IOException e)
+            {
+                // ignore - they'll find out soon enough!
+            }
+        }
+
+        if (MAX_MEMORY > Integer.MAX_VALUE)
+        {
+            return Integer.MAX_VALUE;
+        }
+
+        return (int)MAX_MEMORY;
+    }
+
+    static int calculateBodyLength(
+        int length)
+    {
+        int count = 1;
+
+        if (length > 127)
+        {
+            int size = 1;
+            int val = length;
+
+            while ((val >>>= 8) != 0)
+            {
+                size++;
+            }
+
+            for (int i = (size - 1) * 8; i >= 0; i -= 8)
+            {
+                count++;
+            }
+        }
+
+        return count;
+    }
+
+    static int calculateTagLength(int tagNo)
+        throws IOException
+    {
+        int length = 1;
+
+        if (tagNo >= 31)
+        {
+            if (tagNo < 128)
+            {
+                length++;
+            }
+            else
+            {
+                byte[] stack = new byte[5];
+                int pos = stack.length;
+
+                stack[--pos] = (byte)(tagNo & 0x7F);
+
+                do
+                {
+                    tagNo >>= 7;
+                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+                }
+                while (tagNo > 127);
+
+                length += stack.length - pos;
+            }
+        }
+
+        return length;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
index 38a91fe..18fc66c 100644
--- a/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.bc;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface BCObjectIdentifiers
 {
@@ -9,43 +9,43 @@
      *
      *  1.3.6.1.4.1.22554
      */
-    public static final DERObjectIdentifier bc = new DERObjectIdentifier("1.3.6.1.4.1.22554");
+    public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554");
 
     /**
      * pbe(1) algorithms
      */
-    public static final DERObjectIdentifier bc_pbe = new DERObjectIdentifier(bc.getId() + ".1");
+    public static final ASN1ObjectIdentifier bc_pbe = new ASN1ObjectIdentifier(bc.getId() + ".1");
 
     /**
      * SHA-1(1)
      */
-    public static final DERObjectIdentifier bc_pbe_sha1 = new DERObjectIdentifier(bc_pbe.getId() + ".1");
+    public static final ASN1ObjectIdentifier bc_pbe_sha1 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".1");
 
     /**
      * SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4))
      */
-    public static final DERObjectIdentifier bc_pbe_sha256 = new DERObjectIdentifier(bc_pbe.getId() + ".2.1");
-    public static final DERObjectIdentifier bc_pbe_sha384 = new DERObjectIdentifier(bc_pbe.getId() + ".2.2");
-    public static final DERObjectIdentifier bc_pbe_sha512 = new DERObjectIdentifier(bc_pbe.getId() + ".2.3");
-    public static final DERObjectIdentifier bc_pbe_sha224 = new DERObjectIdentifier(bc_pbe.getId() + ".2.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");
 
     /**
      * PKCS-5(1)|PKCS-12(2)
      */
-    public static final DERObjectIdentifier bc_pbe_sha1_pkcs5 = new DERObjectIdentifier(bc_pbe_sha1.getId() + ".1");
-    public static final DERObjectIdentifier bc_pbe_sha1_pkcs12 = new DERObjectIdentifier(bc_pbe_sha1.getId() + ".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");
 
-    public static final DERObjectIdentifier bc_pbe_sha256_pkcs5 = new DERObjectIdentifier(bc_pbe_sha256.getId() + ".1");
-    public static final DERObjectIdentifier bc_pbe_sha256_pkcs12 = new DERObjectIdentifier(bc_pbe_sha256.getId() + ".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");
 
     /**
      * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
      */
-    public static final DERObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new DERObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.2");
-    public static final DERObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new DERObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.22");
-    public static final DERObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new DERObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.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");
 
-    public static final DERObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new DERObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.2");
-    public static final DERObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new DERObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.22");
-    public static final DERObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new DERObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".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");
 }
diff --git a/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
index f222d9e..a66c4a1 100644
--- a/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
@@ -2,36 +2,36 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERTaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
 
 public class ContentInfo
-    extends ASN1Encodable
+    extends ASN1Object
     // BEGIN android-removed
     // implements CMSObjectIdentifiers
     // END android-removed
 {
     private ASN1ObjectIdentifier contentType;
-    private DEREncodable        content;
+    private ASN1Encodable        content;
 
     public static ContentInfo getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof ContentInfo)
+        if (obj instanceof ContentInfo)
         {
             return (ContentInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new ContentInfo((ASN1Sequence)obj);
+            return new ContentInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public ContentInfo(
@@ -58,7 +58,7 @@
 
     public ContentInfo(
         ASN1ObjectIdentifier contentType,
-        DEREncodable        content)
+        ASN1Encodable        content)
     {
         this.contentType = contentType;
         this.content = content;
@@ -69,7 +69,7 @@
         return contentType;
     }
 
-    public DEREncodable getContent()
+    public ASN1Encodable getContent()
     {
         return content;
     }
@@ -83,7 +83,7 @@
      *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
index b5d6c1f..dba5f6d 100644
--- a/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.cryptopro;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface CryptoProObjectIdentifiers
 {
@@ -8,38 +8,38 @@
     // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)}
     static final String                 GOST_id              = "1.2.643.2.2";
 
-    static final DERObjectIdentifier    gostR3411          = new DERObjectIdentifier(GOST_id+".9");
+    static final ASN1ObjectIdentifier    gostR3411          = new ASN1ObjectIdentifier(GOST_id+".9");
     
-    static final DERObjectIdentifier    gostR28147_cbc     = new DERObjectIdentifier(GOST_id+".21");
+    static final ASN1ObjectIdentifier    gostR28147_cbc     = new ASN1ObjectIdentifier(GOST_id+".21");
 
-    static final DERObjectIdentifier    gostR3410_94       = new DERObjectIdentifier(GOST_id+".20");
-    static final DERObjectIdentifier    gostR3410_2001     = new DERObjectIdentifier(GOST_id+".19");
-    static final DERObjectIdentifier    gostR3411_94_with_gostR3410_94   = new DERObjectIdentifier(GOST_id+".4");
-    static final DERObjectIdentifier    gostR3411_94_with_gostR3410_2001 = new DERObjectIdentifier(GOST_id+".3");
+    static final ASN1ObjectIdentifier    gostR3410_94       = new ASN1ObjectIdentifier(GOST_id+".20");
+    static final ASN1ObjectIdentifier    gostR3410_2001     = new ASN1ObjectIdentifier(GOST_id+".19");
+    static final ASN1ObjectIdentifier    gostR3411_94_with_gostR3410_94   = new ASN1ObjectIdentifier(GOST_id+".4");
+    static final ASN1ObjectIdentifier    gostR3411_94_with_gostR3410_2001 = new ASN1ObjectIdentifier(GOST_id+".3");
 
     // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) }
-    static final DERObjectIdentifier    gostR3411_94_CryptoProParamSet = new DERObjectIdentifier(GOST_id+".30.1");
+    static final ASN1ObjectIdentifier    gostR3411_94_CryptoProParamSet = new ASN1ObjectIdentifier(GOST_id+".30.1");
 
     // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) }
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_A     = new DERObjectIdentifier(GOST_id+".32.2");
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_B     = new DERObjectIdentifier(GOST_id+".32.3");
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_C     = new DERObjectIdentifier(GOST_id+".32.4");
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_D     = new DERObjectIdentifier(GOST_id+".32.5");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_A     = new ASN1ObjectIdentifier(GOST_id+".32.2");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_B     = new ASN1ObjectIdentifier(GOST_id+".32.3");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_C     = new ASN1ObjectIdentifier(GOST_id+".32.4");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_D     = new ASN1ObjectIdentifier(GOST_id+".32.5");
 
     // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) }
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_XchA  = new DERObjectIdentifier(GOST_id+".33.1");
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_XchB  = new DERObjectIdentifier(GOST_id+".33.2");
-    static final DERObjectIdentifier    gostR3410_94_CryptoPro_XchC  = new DERObjectIdentifier(GOST_id+".33.3");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_XchA  = new ASN1ObjectIdentifier(GOST_id+".33.1");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_XchB  = new ASN1ObjectIdentifier(GOST_id+".33.2");
+    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_XchC  = new ASN1ObjectIdentifier(GOST_id+".33.3");
 
     //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) }
-    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_A = new DERObjectIdentifier(GOST_id+".35.1");
-    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_B = new DERObjectIdentifier(GOST_id+".35.2");
-    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_C = new DERObjectIdentifier(GOST_id+".35.3");
+    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_A = new ASN1ObjectIdentifier(GOST_id+".35.1");
+    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_B = new ASN1ObjectIdentifier(GOST_id+".35.2");
+    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_C = new ASN1ObjectIdentifier(GOST_id+".35.3");
 
     // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) }
-    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_XchA  = new DERObjectIdentifier(GOST_id+".36.0");
-    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_XchB  = new DERObjectIdentifier(GOST_id+".36.1");
+    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_XchA  = new ASN1ObjectIdentifier(GOST_id+".36.0");
+    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_XchB  = new ASN1ObjectIdentifier(GOST_id+".36.1");
     
-    static final DERObjectIdentifier    gost_ElSgDH3410_default    = new DERObjectIdentifier(GOST_id+".36.0");
-    static final DERObjectIdentifier    gost_ElSgDH3410_1          = new DERObjectIdentifier(GOST_id+".36.1");
+    static final ASN1ObjectIdentifier    gost_ElSgDH3410_default    = new ASN1ObjectIdentifier(GOST_id+".36.0");
+    static final ASN1ObjectIdentifier    gost_ElSgDH3410_1          = new ASN1ObjectIdentifier(GOST_id+".36.1");
 }
diff --git a/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java b/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
index 61a851a..846a205 100644
--- a/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
+++ b/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.misc;
 
-import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.DERBitString;
 
 /**
  * The NetscapeCertType object.
diff --git a/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java b/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
index ba35d08..c0347da 100644
--- a/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
+++ b/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.misc;
 
-import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.DERIA5String;
 
 public class NetscapeRevocationURL
     extends DERIA5String
diff --git a/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java b/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
index 5066ec5..f09880a 100644
--- a/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
+++ b/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.misc;
 
-import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.DERIA5String;
 
 public class VerisignCzagExtension
     extends DERIA5String
diff --git a/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
index 821e0d1..97712b5 100644
--- a/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
+++ b/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
@@ -1,14 +1,14 @@
 package org.bouncycastle.asn1.nist;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.sec.SECNamedCurves;
 import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
 import org.bouncycastle.asn1.x9.X9ECParameters;
 import org.bouncycastle.util.Strings;
 
-import java.util.Enumeration;
-import java.util.Hashtable;
-
 /**
  * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
  */
@@ -17,7 +17,7 @@
     static final Hashtable objIds = new Hashtable();
     static final Hashtable names = new Hashtable();
 
-    static void defineCurve(String name, DERObjectIdentifier oid)
+    static void defineCurve(String name, ASN1ObjectIdentifier oid)
     {
         objIds.put(name, oid);
         names.put(oid, name);
@@ -42,7 +42,7 @@
     public static X9ECParameters getByName(
         String  name)
     {
-        DERObjectIdentifier oid = (DERObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));
 
         if (oid != null)
         {
@@ -59,7 +59,7 @@
      * @param oid an object identifier representing a named curve, if present.
      */
     public static X9ECParameters getByOID(
-        DERObjectIdentifier  oid)
+        ASN1ObjectIdentifier  oid)
     {
         return SECNamedCurves.getByOID(oid);
     }
@@ -70,17 +70,17 @@
      *
      * @return the object identifier associated with name, if present.
      */
-    public static DERObjectIdentifier getOID(
+    public static ASN1ObjectIdentifier getOID(
         String  name)
     {
-        return (DERObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+        return (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));
     }
 
     /**
      * return the named curve name represented by the given object identifier.
      */
     public static String getName(
-        DERObjectIdentifier  oid)
+        ASN1ObjectIdentifier  oid)
     {
         return (String)names.get(oid);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
index fe04a5c..ea4779b 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
@@ -1,17 +1,19 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.BERSequence;
-import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DLSequence;
 
 public class AuthenticatedSafe
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    ContentInfo[]    info;
+    private ContentInfo[]    info;
+    private boolean  isBer = true;
 
-    public AuthenticatedSafe(
+    private AuthenticatedSafe(
         ASN1Sequence  seq)
     {
         info = new ContentInfo[seq.size()];
@@ -20,6 +22,24 @@
         {
             info[i] = ContentInfo.getInstance(seq.getObjectAt(i));
         }
+
+        isBer = seq instanceof BERSequence;
+    }
+
+    public static AuthenticatedSafe getInstance(
+        Object o)
+    {
+        if (o instanceof AuthenticatedSafe)
+        {
+            return (AuthenticatedSafe)o;
+        }
+
+        if (o != null)
+        {
+            return new AuthenticatedSafe(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
     }
 
     public AuthenticatedSafe(
@@ -33,15 +53,22 @@
         return info;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector();
 
         for (int i = 0; i != info.length; i++)
         {
             v.add(info[i]);
         }
 
-        return new BERSequence(v);
+        if (isBer)
+        {
+            return new BERSequence(v);
+        }
+        else
+        {
+            return new DLSequence(v);
+        }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java b/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
new file mode 100644
index 0000000..b91c1a5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class CRLBag
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier crlId;
+    private ASN1Encodable crlValue;
+
+    private CRLBag(
+        ASN1Sequence seq)
+    {
+        this.crlId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        this.crlValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+    }
+
+    public static CRLBag getInstance(Object o)
+    {
+        if (o instanceof CRLBag)
+        {
+            return (CRLBag)o;
+        }
+        else if (o != null)
+        {
+            return new CRLBag(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public CRLBag(
+        ASN1ObjectIdentifier crlId,
+        ASN1Encodable crlValue)
+    {
+        this.crlId = crlId;
+        this.crlValue = crlValue;
+    }
+
+    public ASN1ObjectIdentifier getcrlId()
+    {
+        return crlId;
+    }
+
+    public ASN1Encodable getCRLValue()
+    {
+        return crlValue;
+    }
+
+    /**
+     * <pre>
+     CRLBag ::= SEQUENCE {
+     crlId  BAG-TYPE.&id ({CRLTypes}),
+     crlValue  [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId})
+     }
+
+     x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}
+     -- DER-encoded X.509 CRL stored in OCTET STRING
+
+     CRLTypes BAG-TYPE ::= {
+     x509CRL,
+     ... -- For future extensions
+     }
+       </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(crlId);
+        v.add(new DERTaggedObject(0, crlValue));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java b/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
index c781b4c..4a73028 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
@@ -2,46 +2,59 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
 public class CertBag
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    ASN1Sequence        seq;
-    DERObjectIdentifier certId;
-    DERObject           certValue;
+    private ASN1ObjectIdentifier certId;
+    private ASN1Encodable certValue;
 
-    public CertBag(
+    private CertBag(
         ASN1Sequence    seq)
     {
-        this.seq = seq;
-        this.certId = (DERObjectIdentifier)seq.getObjectAt(0);
+        this.certId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
         this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
     }
 
+    public static CertBag getInstance(Object o)
+    {
+        if (o instanceof CertBag)
+        {
+            return (CertBag)o;
+        }
+        else if (o != null)
+        {
+            return new CertBag(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
     public CertBag(
-        DERObjectIdentifier certId,
-        DERObject           certValue)
+        ASN1ObjectIdentifier certId,
+        ASN1Encodable        certValue)
     {
         this.certId = certId;
         this.certValue = certValue;
     }
 
-    public DERObjectIdentifier getCertId()
+    public ASN1ObjectIdentifier getCertId()
     {
         return certId;
     }
 
-    public DERObject getCertValue()
+    public ASN1Encodable getCertValue()
     {
         return certValue;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
index 73c2e94..987d4eb 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
@@ -1,10 +1,10 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
@@ -19,7 +19,7 @@
  * </pre>
  */
 public class CertificationRequest
-    extends ASN1Encodable
+    extends ASN1Object
 {
     protected CertificationRequestInfo reqInfo = null;
     protected AlgorithmIdentifier sigAlgId = null;
@@ -77,7 +77,7 @@
         return sigBits;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         // Construct the CertificateRequest
         ASN1EncodableVector  v = new ASN1EncodableVector();
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
index bf3b0a8..aac2bb7 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
@@ -1,11 +1,11 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.ASN1Set;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x500.X500Name;
@@ -31,10 +31,10 @@
  * </pre>
  */
 public class CertificationRequestInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    DERInteger              version = new DERInteger(0);
-    X509Name                subject;
+    ASN1Integer              version = new ASN1Integer(0);
+    X500Name                subject;
     SubjectPublicKeyInfo    subjectPKInfo;
     ASN1Set                 attributes = null;
 
@@ -45,12 +45,12 @@
         {
             return (CertificationRequestInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new CertificationRequestInfo((ASN1Sequence)obj);
+            return new CertificationRequestInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public CertificationRequestInfo(
@@ -58,21 +58,6 @@
         SubjectPublicKeyInfo    pkInfo,
         ASN1Set                 attributes)
     {
-        this.subject = X509Name.getInstance(subject.getDERObject());
-        this.subjectPKInfo = pkInfo;
-        this.attributes = attributes;
-
-        if ((subject == null) || (version == null) || (subjectPKInfo == null))
-        {
-            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
-        }
-    }
-
-    public CertificationRequestInfo(
-        X509Name                subject,
-        SubjectPublicKeyInfo    pkInfo,
-        ASN1Set                 attributes)
-    {
         this.subject = subject;
         this.subjectPKInfo = pkInfo;
         this.attributes = attributes;
@@ -83,12 +68,30 @@
         }
     }
 
+    /**
+     * @deprecated use X500Name method.
+     */
+    public CertificationRequestInfo(
+        X509Name                subject,
+        SubjectPublicKeyInfo    pkInfo,
+        ASN1Set                 attributes)
+    {
+        this.subject = X500Name.getInstance(subject.toASN1Primitive());
+        this.subjectPKInfo = pkInfo;
+        this.attributes = attributes;
+
+        if ((subject == null) || (version == null) || (subjectPKInfo == null))
+        {
+            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+        }
+    }
+
     public CertificationRequestInfo(
         ASN1Sequence  seq)
     {
-        version = (DERInteger)seq.getObjectAt(0);
+        version = (ASN1Integer)seq.getObjectAt(0);
 
-        subject = X509Name.getInstance(seq.getObjectAt(1));
+        subject = X500Name.getInstance(seq.getObjectAt(1));
         subjectPKInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(2));
 
         //
@@ -107,12 +110,12 @@
         }
     }
 
-    public DERInteger getVersion()
+    public ASN1Integer getVersion()
     {
         return version;
     }
 
-    public X509Name getSubject()
+    public X500Name getSubject()
     {
         return subject;
     }
@@ -127,7 +130,7 @@
         return attributes;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
index 6b56c1a..1ee920f 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
@@ -4,20 +4,22 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERTaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DLSequence;
 
 public class ContentInfo
-    extends ASN1Encodable
+    extends ASN1Object
     implements PKCSObjectIdentifiers
 {
-    private DERObjectIdentifier contentType;
-    private DEREncodable        content;
+    private ASN1ObjectIdentifier contentType;
+    private ASN1Encodable content;
+    private boolean       isBer = true;
 
     public static ContentInfo getInstance(
         Object  obj)
@@ -26,41 +28,44 @@
         {
             return (ContentInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+
+        if (obj != null)
         {
-            return new ContentInfo((ASN1Sequence)obj);
+            return new ContentInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
-    public ContentInfo(
+    private ContentInfo(
         ASN1Sequence  seq)
     {
         Enumeration   e = seq.getObjects();
 
-        contentType = (DERObjectIdentifier)e.nextElement();
+        contentType = (ASN1ObjectIdentifier)e.nextElement();
 
         if (e.hasMoreElements())
         {
-            content = ((DERTaggedObject)e.nextElement()).getObject();
+            content = ((ASN1TaggedObject)e.nextElement()).getObject();
         }
+
+        isBer = seq instanceof BERSequence;
     }
 
     public ContentInfo(
-        DERObjectIdentifier contentType,
-        DEREncodable        content)
+        ASN1ObjectIdentifier contentType,
+        ASN1Encodable content)
     {
         this.contentType = contentType;
         this.content = content;
     }
 
-    public DERObjectIdentifier getContentType()
+    public ASN1ObjectIdentifier getContentType()
     {
         return contentType;
     }
 
-    public DEREncodable getContent()
+    public ASN1Encodable getContent()
     {
         return content;
     }
@@ -74,17 +79,24 @@
      *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector();
 
         v.add(contentType);
 
         if (content != null)
         {
-            v.add(new BERTaggedObject(0, content));
+            v.add(new BERTaggedObject(true, 0, content));
         }
 
-        return new BERSequence(v);
+        if (isBer)
+        {
+            return new BERSequence(v);
+        }
+        else
+        {
+            return new DLSequence(v);
+        }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java b/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
index 34537fa..fa22f79 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
@@ -3,29 +3,29 @@
 import java.math.BigInteger;
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class DHParameter
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    DERInteger      p, g, l;
+    ASN1Integer      p, g, l;
 
     public DHParameter(
         BigInteger  p,
         BigInteger  g,
         int         l)
     {
-        this.p = new DERInteger(p);
-        this.g = new DERInteger(g);
+        this.p = new ASN1Integer(p);
+        this.g = new ASN1Integer(g);
 
         if (l != 0)
         {
-            this.l = new DERInteger(l);
+            this.l = new ASN1Integer(l);
         }
         else
         {
@@ -33,17 +33,33 @@
         }
     }
 
-    public DHParameter(
+    public static DHParameter getInstance(
+        Object  obj)
+    {
+        if (obj instanceof DHParameter)
+        {
+            return (DHParameter)obj;
+        }
+
+        if (obj != null)
+        {
+            return new DHParameter(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private DHParameter(
         ASN1Sequence  seq)
     {
         Enumeration     e = seq.getObjects();
 
-        p = (DERInteger)e.nextElement();
-        g = (DERInteger)e.nextElement();
+        p = ASN1Integer.getInstance(e.nextElement());
+        g = ASN1Integer.getInstance(e.nextElement());
 
         if (e.hasMoreElements())
         {
-            l = (DERInteger)e.nextElement();
+            l = (ASN1Integer)e.nextElement();
         }
         else
         {
@@ -71,7 +87,7 @@
         return l.getPositiveValue();
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
index 7fa8e08..e0f5efd 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
@@ -2,15 +2,15 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERTaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 /**
@@ -32,11 +32,11 @@
  * </pre>
  */
 public class EncryptedData
-    extends ASN1Encodable
+    extends ASN1Object
 {
     ASN1Sequence                data;
-    DERObjectIdentifier         bagId;
-    DERObject                   bagValue;
+    ASN1ObjectIdentifier bagId;
+    ASN1Primitive bagValue;
 
     public static EncryptedData getInstance(
          Object  obj)
@@ -45,44 +45,45 @@
          {
              return (EncryptedData)obj;
          }
-         else if (obj instanceof ASN1Sequence)
+
+         if (obj != null)
          {
-             return new EncryptedData((ASN1Sequence)obj);
+             return new EncryptedData(ASN1Sequence.getInstance(obj));
          }
 
-         throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+         return null;
     }
      
-    public EncryptedData(
+    private EncryptedData(
         ASN1Sequence seq)
     {
-        int version = ((DERInteger)seq.getObjectAt(0)).getValue().intValue();
+        int version = ((ASN1Integer)seq.getObjectAt(0)).getValue().intValue();
 
         if (version != 0)
         {
             throw new IllegalArgumentException("sequence not version 0");
         }
 
-        this.data = (ASN1Sequence)seq.getObjectAt(1);
+        this.data = ASN1Sequence.getInstance(seq.getObjectAt(1));
     }
 
     public EncryptedData(
-        DERObjectIdentifier     contentType,
+        ASN1ObjectIdentifier contentType,
         AlgorithmIdentifier     encryptionAlgorithm,
-        DEREncodable            content)
+        ASN1Encodable content)
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
         v.add(contentType);
-        v.add(encryptionAlgorithm.getDERObject());
+        v.add(encryptionAlgorithm.toASN1Primitive());
         v.add(new BERTaggedObject(false, 0, content));
 
         data = new BERSequence(v);
     }
         
-    public DERObjectIdentifier getContentType()
+    public ASN1ObjectIdentifier getContentType()
     {
-        return (DERObjectIdentifier)data.getObjectAt(0);
+        return ASN1ObjectIdentifier.getInstance(data.getObjectAt(0));
     }
 
     public AlgorithmIdentifier getEncryptionAlgorithm()
@@ -94,7 +95,7 @@
     {
         if (data.size() == 3)
         {
-            DERTaggedObject o = (DERTaggedObject)data.getObjectAt(2);
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(data.getObjectAt(2));
 
             return ASN1OctetString.getInstance(o, false);
         }
@@ -102,11 +103,11 @@
         return null;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(0));
+        v.add(new ASN1Integer(0));
         v.add(data);
 
         return new BERSequence(v);
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
index 0ca629a..2aa2fae 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
@@ -2,28 +2,28 @@
 
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 public class EncryptedPrivateKeyInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private AlgorithmIdentifier algId;
     private ASN1OctetString     data;
 
-    public EncryptedPrivateKeyInfo(
+    private EncryptedPrivateKeyInfo(
         ASN1Sequence  seq)
     {
         Enumeration e = seq.getObjects();
 
         algId = AlgorithmIdentifier.getInstance(e.nextElement());
-        data = (ASN1OctetString)e.nextElement();
+        data = ASN1OctetString.getInstance(e.nextElement());
     }
 
     public EncryptedPrivateKeyInfo(
@@ -44,12 +44,12 @@
             return (EncryptedPrivateKeyInfo)obj;
         }
         // END android-changed
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         { 
-            return new EncryptedPrivateKeyInfo((ASN1Sequence)obj);
+            return new EncryptedPrivateKeyInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
     public AlgorithmIdentifier getEncryptionAlgorithm()
@@ -77,7 +77,7 @@
      * }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
index 8f06c23..613c3f4 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
@@ -1,10 +1,10 @@
 package org.bouncycastle.asn1.pkcs;
 
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
@@ -12,8 +12,8 @@
     extends AlgorithmIdentifier
 {
     public EncryptionScheme(
-        DERObjectIdentifier objectId,
-        DEREncodable parameters)
+        ASN1ObjectIdentifier objectId,
+        ASN1Encodable parameters)
     {
         super(objectId, parameters);
     }
@@ -21,7 +21,7 @@
     EncryptionScheme(
         ASN1Sequence  seq)
     {   
-        this((DERObjectIdentifier)seq.getObjectAt(0), seq.getObjectAt(1));
+        this((ASN1ObjectIdentifier)seq.getObjectAt(0), seq.getObjectAt(1));
     }
 
     public static final AlgorithmIdentifier getInstance(Object obj)
@@ -38,12 +38,12 @@
         throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
     }
 
-    public DERObject getObject()
+    public ASN1Primitive getObject()
     {
-        return (DERObject)getParameters();
+        return (ASN1Primitive)getParameters();
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive getASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java b/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
index 699e467..bb94440 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
@@ -2,19 +2,20 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.X509Name;
 
 public class IssuerAndSerialNumber
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    X509Name    name;
-    DERInteger  certSerialNumber;
+    X500Name name;
+    ASN1Integer  certSerialNumber;
 
     public static IssuerAndSerialNumber getInstance(
         Object  obj)
@@ -34,37 +35,45 @@
     public IssuerAndSerialNumber(
         ASN1Sequence    seq)
     {
-        this.name = X509Name.getInstance(seq.getObjectAt(0));
-        this.certSerialNumber = (DERInteger)seq.getObjectAt(1);
+        this.name = X500Name.getInstance(seq.getObjectAt(0));
+        this.certSerialNumber = (ASN1Integer)seq.getObjectAt(1);
     }
 
     public IssuerAndSerialNumber(
         X509Name    name,
         BigInteger  certSerialNumber)
     {
-        this.name = name;
-        this.certSerialNumber = new DERInteger(certSerialNumber);
+        this.name = X500Name.getInstance(name.toASN1Primitive());
+        this.certSerialNumber = new ASN1Integer(certSerialNumber);
     }
 
     public IssuerAndSerialNumber(
         X509Name    name,
-        DERInteger  certSerialNumber)
+        ASN1Integer  certSerialNumber)
     {
-        this.name = name;
+        this.name = X500Name.getInstance(name.toASN1Primitive());
         this.certSerialNumber = certSerialNumber;
     }
 
-    public X509Name getName()
+    public IssuerAndSerialNumber(
+        X500Name    name,
+        BigInteger  certSerialNumber)
+    {
+        this.name = name;
+        this.certSerialNumber = new ASN1Integer(certSerialNumber);
+    }
+
+    public X500Name getName()
     {
         return name;
     }
 
-    public DERInteger getCertificateSerialNumber()
+    public ASN1Integer getCertificateSerialNumber()
     {
         return certSerialNumber;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector    v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
index 08dd94f..fef4f07 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
@@ -1,8 +1,8 @@
 package org.bouncycastle.asn1.pkcs;
 
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 public class KeyDerivationFunc
@@ -15,7 +15,7 @@
     }
     
     public KeyDerivationFunc(
-        DERObjectIdentifier id,
+        ASN1ObjectIdentifier id,
         ASN1Encodable       params)
     {
         super(id, params);
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java b/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
index e85cf4a..1d8f582 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
@@ -2,18 +2,18 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.DigestInfo;
 
 public class MacData
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private static final BigInteger ONE = BigInteger.valueOf(1);
 
@@ -28,15 +28,15 @@
         {
             return (MacData)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new MacData((ASN1Sequence)obj);
+            return new MacData(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
-    public MacData(
+    private MacData(
         ASN1Sequence seq)
     {
         this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0));
@@ -45,7 +45,7 @@
 
         if (seq.size() == 3)
         {
-            this.iterationCount = ((DERInteger)seq.getObjectAt(2)).getValue();
+            this.iterationCount = ((ASN1Integer)seq.getObjectAt(2)).getValue();
         }
         else
         {
@@ -87,9 +87,9 @@
      *     -- Note: The default is for historic reasons and its use is deprecated. A
      *     -- higher value, like 1024 is recommended.
      * </pre>
-     * @return the basic DERObject construction.
+     * @return the basic ASN1Primitive construction.
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
@@ -98,7 +98,7 @@
         
         if (!iterationCount.equals(ONE))
         {
-            v.add(new DERInteger(iterationCount));
+            v.add(new ASN1Integer(iterationCount));
         }
 
         return new DERSequence(v);
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java b/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
index f24cd9a..06180df 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
@@ -2,19 +2,19 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 
 public class PBEParameter
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    DERInteger      iterations;
+    ASN1Integer      iterations;
     ASN1OctetString salt;
 
     public PBEParameter(
@@ -26,14 +26,14 @@
             throw new IllegalArgumentException("salt length must be 8");
         }
         this.salt = new DEROctetString(salt);
-        this.iterations = new DERInteger(iterations);
+        this.iterations = new ASN1Integer(iterations);
     }
 
-    public PBEParameter(
+    private PBEParameter(
         ASN1Sequence  seq)
     {
         salt = (ASN1OctetString)seq.getObjectAt(0);
-        iterations = (DERInteger)seq.getObjectAt(1);
+        iterations = (ASN1Integer)seq.getObjectAt(1);
     }
 
     public static PBEParameter getInstance(
@@ -43,12 +43,12 @@
         {
             return (PBEParameter)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new PBEParameter((ASN1Sequence)obj);
+            return new PBEParameter(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public BigInteger getIterationCount()
@@ -61,7 +61,7 @@
         return salt.getOctets();
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
@@ -70,4 +70,4 @@
 
         return new DERSequence(v);
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java b/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
index 2817903..06c9455 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
@@ -3,9 +3,9 @@
 import java.util.Enumeration;
 
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
@@ -15,7 +15,7 @@
 public class PBES2Algorithms
     extends AlgorithmIdentifier implements PKCSObjectIdentifiers
 {
-    private DERObjectIdentifier objectId;
+    private ASN1ObjectIdentifier objectId;
     private KeyDerivationFunc   func;
     private EncryptionScheme    scheme;
 
@@ -26,7 +26,7 @@
 
         Enumeration     e = obj.getObjects();
 
-        objectId = (DERObjectIdentifier)e.nextElement();
+        objectId = (ASN1ObjectIdentifier)e.nextElement();
 
         ASN1Sequence seq = (ASN1Sequence)e.nextElement();
 
@@ -46,7 +46,7 @@
         scheme = new EncryptionScheme((ASN1Sequence)e.nextElement());
     }
 
-    public DERObjectIdentifier getObjectId()
+    public ASN1ObjectIdentifier getObjectId()
     {
         return objectId;
     }
@@ -61,7 +61,7 @@
         return scheme;
     }
 
-    public DERObject getDERObject()
+    public ASN1Primitive getASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
         ASN1EncodableVector  subV = new ASN1EncodableVector();
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
index c96d169..5ada493 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
@@ -4,13 +4,13 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class PBES2Parameters
-    extends ASN1Encodable
+    extends ASN1Object
     implements PKCSObjectIdentifiers
 {
     private KeyDerivationFunc   func;
@@ -36,7 +36,7 @@
         ASN1Sequence  obj)
     {
         Enumeration e = obj.getObjects();
-        ASN1Sequence  funcSeq = ASN1Sequence.getInstance(((DEREncodable)e.nextElement()).getDERObject());
+        ASN1Sequence  funcSeq = ASN1Sequence.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());
 
         if (funcSeq.getObjectAt(0).equals(id_PBKDF2))
         {
@@ -60,7 +60,7 @@
         return scheme;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
index 02b1543..f46c294 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
@@ -3,21 +3,21 @@
 import java.math.BigInteger;
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 
 public class PBKDF2Params
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    ASN1OctetString     octStr;
-    DERInteger          iterationCount;
-    DERInteger          keyLength;
+    private ASN1OctetString octStr;
+    private ASN1Integer      iterationCount;
+    private ASN1Integer      keyLength;
 
     public static PBKDF2Params getInstance(
         Object  obj)
@@ -27,12 +27,12 @@
             return (PBKDF2Params)obj;
         }
 
-        if (obj instanceof ASN1Sequence)
+        if (obj != null)
         {
-            return new PBKDF2Params((ASN1Sequence)obj);
+            return new PBKDF2Params(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
     public PBKDF2Params(
@@ -40,20 +40,30 @@
         int     iterationCount)
     {
         this.octStr = new DEROctetString(salt);
-        this.iterationCount = new DERInteger(iterationCount);
+        this.iterationCount = new ASN1Integer(iterationCount);
     }
-    
+
     public PBKDF2Params(
+        byte[]  salt,
+        int     iterationCount,
+        int     keyLength)
+    {
+    	this(salt, iterationCount);
+
+        this.keyLength = new ASN1Integer(keyLength);
+    }
+
+    private PBKDF2Params(
         ASN1Sequence  seq)
     {
         Enumeration e = seq.getObjects();
 
         octStr = (ASN1OctetString)e.nextElement();
-        iterationCount = (DERInteger)e.nextElement();
+        iterationCount = (ASN1Integer)e.nextElement();
 
         if (e.hasMoreElements())
         {
-            keyLength = (DERInteger)e.nextElement();
+            keyLength = (ASN1Integer)e.nextElement();
         }
         else
         {
@@ -81,7 +91,7 @@
         return null;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
index 8817b35..0ddf5c3 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
@@ -2,19 +2,19 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 
 public class PKCS12PBEParams
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    DERInteger      iterations;
+    ASN1Integer      iterations;
     ASN1OctetString iv;
 
     public PKCS12PBEParams(
@@ -22,14 +22,14 @@
         int         iterations)
     {
         this.iv = new DEROctetString(salt);
-        this.iterations = new DERInteger(iterations);
+        this.iterations = new ASN1Integer(iterations);
     }
 
-    public PKCS12PBEParams(
+    private PKCS12PBEParams(
         ASN1Sequence  seq)
     {
         iv = (ASN1OctetString)seq.getObjectAt(0);
-        iterations = (DERInteger)seq.getObjectAt(1);
+        iterations = ASN1Integer.getInstance(seq.getObjectAt(1));
     }
 
     public static PKCS12PBEParams getInstance(
@@ -39,12 +39,12 @@
         {
             return (PKCS12PBEParams)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new PKCS12PBEParams((ASN1Sequence)obj);
+            return new PKCS12PBEParams(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public BigInteger getIterations()
@@ -57,7 +57,7 @@
         return iv.getOctets();
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
index 7bec34b..fa4c20e 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -254,6 +254,11 @@
     static final ASN1ObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3");
     static final ASN1ObjectIdentifier    pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4");
     static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5");
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
+
+    /**
+     * @deprecated use pbeWithSHAAnd40BitRC2_CBC
+     */
     static final ASN1ObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
 
     static final ASN1ObjectIdentifier    id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6");
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java b/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
index ba5292c..7885a79 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
@@ -2,27 +2,27 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.BERSequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 
 /**
  * the infamous Pfx from PKCS12
  */
 public class Pfx
-    extends ASN1Encodable
+    extends ASN1Object
     implements PKCSObjectIdentifiers
 {
     private ContentInfo             contentInfo;
     private MacData                 macData = null;
 
-    public Pfx(
+    private Pfx(
         ASN1Sequence   seq)
     {
-        BigInteger  version = ((DERInteger)seq.getObjectAt(0)).getValue();
+        BigInteger  version = ((ASN1Integer)seq.getObjectAt(0)).getValue();
         if (version.intValue() != 3)
         {
             throw new IllegalArgumentException("wrong version for PFX PDU");
@@ -36,6 +36,22 @@
         }
     }
 
+    public static Pfx getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Pfx)
+        {
+            return (Pfx)obj;
+        }
+
+        if (obj != null)
+        {
+            return new Pfx(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
     public Pfx(
         ContentInfo     contentInfo,
         MacData         macData)
@@ -54,11 +70,11 @@
         return macData;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(3));
+        v.add(new ASN1Integer(3));
         v.add(contentInfo);
 
         if (macData != null)
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
index 9e84499..6b42763 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
@@ -6,22 +6,23 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Encoding;
+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.ASN1Set;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 public class PrivateKeyInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERObject               privKey;
+    private ASN1OctetString         privKey;
     private AlgorithmIdentifier     algId;
     private ASN1Set                 attributes;
 
@@ -49,17 +50,19 @@
         
     public PrivateKeyInfo(
         AlgorithmIdentifier algId,
-        DERObject           privateKey)
+        ASN1Encodable       privateKey)
+        throws IOException
     {
         this(algId, privateKey, null);
     }
 
     public PrivateKeyInfo(
         AlgorithmIdentifier algId,
-        DERObject           privateKey,
+        ASN1Encodable       privateKey,
         ASN1Set             attributes)
+        throws IOException
     {
-        this.privKey = privateKey;
+        this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER));
         this.algId = algId;
         this.attributes = attributes;
     }
@@ -69,24 +72,14 @@
     {
         Enumeration e = seq.getObjects();
 
-        BigInteger  version = ((DERInteger)e.nextElement()).getValue();
+        BigInteger  version = ((ASN1Integer)e.nextElement()).getValue();
         if (version.intValue() != 0)
         {
             throw new IllegalArgumentException("wrong version for private key info");
         }
 
-        algId = new AlgorithmIdentifier((ASN1Sequence)e.nextElement());
-
-        try
-        {
-            ASN1InputStream         aIn = new ASN1InputStream(((ASN1OctetString)e.nextElement()).getOctets());
-
-            privKey = aIn.readObject();
-        }
-        catch (IOException ex)
-        {
-            throw new IllegalArgumentException("Error recoverying private key from sequence");
-        }
+        algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        privKey = ASN1OctetString.getInstance(e.nextElement());
         
         if (e.hasMoreElements())
         {
@@ -94,14 +87,37 @@
         }
     }
 
+    public AlgorithmIdentifier getPrivateKeyAlgorithm()
+    {
+        return algId;
+    }
+        /**
+          * @deprecated use getPrivateKeyAlgorithm()
+     */
     public AlgorithmIdentifier getAlgorithmId()
     {
         return algId;
     }
 
-    public DERObject getPrivateKey()
+    public ASN1Encodable parsePrivateKey()
+        throws IOException
     {
-        return privKey;
+        return ASN1Primitive.fromByteArray(privKey.getOctets());
+    }
+
+    /**
+          * @deprecated use parsePrivateKey()
+     */
+    public ASN1Primitive getPrivateKey()
+    {
+        try
+        {
+            return parsePrivateKey().toASN1Primitive();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("unable to parse private key");
+        }
     }
     
     public ASN1Set getAttributes()
@@ -126,13 +142,13 @@
      *      Attributes ::= SET OF Attribute
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(0));
+        v.add(new ASN1Integer(0));
         v.add(algId);
-        v.add(new DEROctetString(privKey));
+        v.add(privKey);
 
         if (attributes != null)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
index 1ded6e9..25ff98d 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
@@ -1,11 +1,11 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
@@ -13,7 +13,7 @@
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 public class RSAESOAEPparams
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private AlgorithmIdentifier hashAlgorithm;
     private AlgorithmIdentifier maskGenAlgorithm;
@@ -32,12 +32,12 @@
         {
             return (RSAESOAEPparams)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new RSAESOAEPparams((ASN1Sequence)obj);
+            return new RSAESOAEPparams(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
     /**
@@ -129,7 +129,7 @@
      * </pre>
      * @return the asn1 primitive representing the parameters.
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
         
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java b/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java
new file mode 100644
index 0000000..36992cf
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java
@@ -0,0 +1,187 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+public class RSAPrivateKey
+    extends ASN1Object
+{
+    private BigInteger version;
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+    private BigInteger privateExponent;
+    private BigInteger prime1;
+    private BigInteger prime2;
+    private BigInteger exponent1;
+    private BigInteger exponent2;
+    private BigInteger coefficient;
+    private ASN1Sequence otherPrimeInfos = null;
+
+    public static RSAPrivateKey getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPrivateKey getInstance(
+        Object obj)
+    {
+        if (obj instanceof RSAPrivateKey)
+        {
+            return (RSAPrivateKey)obj;
+        }
+
+        if (obj != null)
+        {
+            return new RSAPrivateKey(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    public RSAPrivateKey(
+        BigInteger modulus,
+        BigInteger publicExponent,
+        BigInteger privateExponent,
+        BigInteger prime1,
+        BigInteger prime2,
+        BigInteger exponent1,
+        BigInteger exponent2,
+        BigInteger coefficient)
+    {
+        this.version = BigInteger.valueOf(0);
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+        this.privateExponent = privateExponent;
+        this.prime1 = prime1;
+        this.prime2 = prime2;
+        this.exponent1 = exponent1;
+        this.exponent2 = exponent2;
+        this.coefficient = coefficient;
+    }
+
+    private RSAPrivateKey(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        BigInteger v = ((ASN1Integer)e.nextElement()).getValue();
+        if (v.intValue() != 0 && v.intValue() != 1)
+        {
+            throw new IllegalArgumentException("wrong version for RSA private key");
+        }
+
+        version = v;
+        modulus = ((ASN1Integer)e.nextElement()).getValue();
+        publicExponent = ((ASN1Integer)e.nextElement()).getValue();
+        privateExponent = ((ASN1Integer)e.nextElement()).getValue();
+        prime1 = ((ASN1Integer)e.nextElement()).getValue();
+        prime2 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent1 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent2 = ((ASN1Integer)e.nextElement()).getValue();
+        coefficient = ((ASN1Integer)e.nextElement()).getValue();
+        
+        if (e.hasMoreElements())
+        {
+            otherPrimeInfos = (ASN1Sequence)e.nextElement();
+        }
+    }
+
+    public BigInteger getVersion()
+    {
+        return version;
+    }
+    
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public BigInteger getPrime1()
+    {
+        return prime1;
+    }
+
+    public BigInteger getPrime2()
+    {
+        return prime2;
+    }
+
+    public BigInteger getExponent1()
+    {
+        return exponent1;
+    }
+
+    public BigInteger getExponent2()
+    {
+        return exponent2;
+    }
+
+    public BigInteger getCoefficient()
+    {
+        return coefficient;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPrivateKey ::= SEQUENCE {
+     *                          version Version,
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                          privateExponent INTEGER, -- d
+     *                          prime1 INTEGER, -- p
+     *                          prime2 INTEGER, -- q
+     *                          exponent1 INTEGER, -- d mod (p-1)
+     *                          exponent2 INTEGER, -- d mod (q-1)
+     *                          coefficient INTEGER, -- (inverse of q) mod p
+     *                          otherPrimeInfos OtherPrimeInfos OPTIONAL
+     *                      }
+     *
+     *      Version ::= INTEGER { two-prime(0), multi(1) }
+     *        (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+     * </pre>
+     * <p>
+     * This routine is written to output PKCS1 version 2.1, private keys.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(version));                       // version
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+        v.add(new ASN1Integer(getPrivateExponent()));
+        v.add(new ASN1Integer(getPrime1()));
+        v.add(new ASN1Integer(getPrime2()));
+        v.add(new ASN1Integer(getExponent1()));
+        v.add(new ASN1Integer(getExponent2()));
+        v.add(new ASN1Integer(getCoefficient()));
+
+        if (otherPrimeInfos != null)
+        {
+            v.add(otherPrimeInfos);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
index e2f0072..5912d5e 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
@@ -3,16 +3,19 @@
 import java.math.BigInteger;
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
+/**
+ * @deprecated use RSAPrivateKey
+ */
 public class RSAPrivateKeyStructure
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private int         version;
     private BigInteger  modulus;
@@ -73,21 +76,21 @@
     {
         Enumeration e = seq.getObjects();
 
-        BigInteger  v = ((DERInteger)e.nextElement()).getValue();
+        BigInteger  v = ((ASN1Integer)e.nextElement()).getValue();
         if (v.intValue() != 0 && v.intValue() != 1)
         {
             throw new IllegalArgumentException("wrong version for RSA private key");
         }
 
         version = v.intValue();
-        modulus = ((DERInteger)e.nextElement()).getValue();
-        publicExponent = ((DERInteger)e.nextElement()).getValue();
-        privateExponent = ((DERInteger)e.nextElement()).getValue();
-        prime1 = ((DERInteger)e.nextElement()).getValue();
-        prime2 = ((DERInteger)e.nextElement()).getValue();
-        exponent1 = ((DERInteger)e.nextElement()).getValue();
-        exponent2 = ((DERInteger)e.nextElement()).getValue();
-        coefficient = ((DERInteger)e.nextElement()).getValue();
+        modulus = ((ASN1Integer)e.nextElement()).getValue();
+        publicExponent = ((ASN1Integer)e.nextElement()).getValue();
+        privateExponent = ((ASN1Integer)e.nextElement()).getValue();
+        prime1 = ((ASN1Integer)e.nextElement()).getValue();
+        prime2 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent1 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent2 = ((ASN1Integer)e.nextElement()).getValue();
+        coefficient = ((ASN1Integer)e.nextElement()).getValue();
         
         if (e.hasMoreElements())
         {
@@ -162,19 +165,19 @@
      * <p>
      * This routine is written to output PKCS1 version 2.1, private keys.
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(version));                       // version
-        v.add(new DERInteger(getModulus()));
-        v.add(new DERInteger(getPublicExponent()));
-        v.add(new DERInteger(getPrivateExponent()));
-        v.add(new DERInteger(getPrime1()));
-        v.add(new DERInteger(getPrime2()));
-        v.add(new DERInteger(getExponent1()));
-        v.add(new DERInteger(getExponent2()));
-        v.add(new DERInteger(getCoefficient()));
+        v.add(new ASN1Integer(version));                       // version
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+        v.add(new ASN1Integer(getPrivateExponent()));
+        v.add(new ASN1Integer(getPrime1()));
+        v.add(new ASN1Integer(getPrime2()));
+        v.add(new ASN1Integer(getExponent1()));
+        v.add(new ASN1Integer(getExponent2()));
+        v.add(new ASN1Integer(getCoefficient()));
 
         if (otherPrimeInfos != null)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java b/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java
new file mode 100644
index 0000000..6c43298
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+public class RSAPublicKey
+    extends ASN1Object
+{
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+
+    public static RSAPublicKey getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPublicKey getInstance(
+        Object obj)
+    {
+        if (obj instanceof RSAPublicKey)
+        {
+            return (RSAPublicKey)obj;
+        }
+
+        if (obj != null)
+        {
+            return new RSAPublicKey(ASN1Sequence.getInstance(obj));
+        }
+        
+        return null;
+    }
+    
+    public RSAPublicKey(
+        BigInteger modulus,
+        BigInteger publicExponent)
+    {
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+    }
+
+    private RSAPublicKey(
+        ASN1Sequence seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        Enumeration e = seq.getObjects();
+
+        modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+        publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPublicKey ::= SEQUENCE {
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                      }
+     * </pre>
+     * <p>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
index bfa3ed6..73cfcdc 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
@@ -1,45 +1,47 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+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.DERInteger;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 public class RSASSAPSSparams
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private AlgorithmIdentifier hashAlgorithm;
     private AlgorithmIdentifier maskGenAlgorithm;
-    private DERInteger          saltLength;
-    private DERInteger          trailerField;
+    private ASN1Integer          saltLength;
+    private ASN1Integer          trailerField;
     
     // BEGIN android-changed
     public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
     // END android-changed
     public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
-    public final static DERInteger          DEFAULT_SALT_LENGTH = new DERInteger(20);
-    public final static DERInteger          DEFAULT_TRAILER_FIELD = new DERInteger(1);
+    public final static ASN1Integer          DEFAULT_SALT_LENGTH = new ASN1Integer(20);
+    public final static ASN1Integer          DEFAULT_TRAILER_FIELD = new ASN1Integer(1);
     
     public static RSASSAPSSparams getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof RSASSAPSSparams)
+        if (obj instanceof RSASSAPSSparams)
         {
             return (RSASSAPSSparams)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new RSASSAPSSparams((ASN1Sequence)obj);
+            return new RSASSAPSSparams(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
     /**
@@ -56,8 +58,8 @@
     public RSASSAPSSparams(
         AlgorithmIdentifier hashAlgorithm,
         AlgorithmIdentifier maskGenAlgorithm,
-        DERInteger          saltLength,
-        DERInteger          trailerField)
+        ASN1Integer          saltLength,
+        ASN1Integer          trailerField)
     {
         this.hashAlgorithm = hashAlgorithm;
         this.maskGenAlgorithm = maskGenAlgorithm;
@@ -65,7 +67,7 @@
         this.trailerField = trailerField;
     }
     
-    public RSASSAPSSparams(
+    private RSASSAPSSparams(
         ASN1Sequence seq)
     {
         hashAlgorithm = DEFAULT_HASH_ALGORITHM;
@@ -86,10 +88,10 @@
                 maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
                 break;
             case 2:
-                saltLength = DERInteger.getInstance(o, true);
+                saltLength = ASN1Integer.getInstance(o, true);
                 break;
             case 3:
-                trailerField = DERInteger.getInstance(o, true);
+                trailerField = ASN1Integer.getInstance(o, true);
                 break;
             default:
                 throw new IllegalArgumentException("unknown tag");
@@ -107,14 +109,14 @@
         return maskGenAlgorithm;
     }
     
-    public DERInteger getSaltLength()
+    public BigInteger getSaltLength()
     {
-        return saltLength;
+        return saltLength.getValue();
     }
     
-    public DERInteger getTrailerField()
+    public BigInteger getTrailerField()
     {
-        return trailerField;
+        return trailerField.getValue();
     }
     
     /**
@@ -143,7 +145,7 @@
      * </pre>
      * @return the asn1 primitive representing the parameters.
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
         
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java b/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
index 2808d92..00ca0a2 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
@@ -2,23 +2,25 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DLSequence;
+import org.bouncycastle.asn1.DLTaggedObject;
 
 public class SafeBag
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    DERObjectIdentifier         bagId;
-    DERObject                   bagValue;
-    ASN1Set                     bagAttributes;
+    private ASN1ObjectIdentifier bagId;
+    private ASN1Encodable bagValue;
+    private ASN1Set                     bagAttributes;
 
     public SafeBag(
-        DERObjectIdentifier     oid,
-        DERObject               obj)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable obj)
     {
         this.bagId = oid;
         this.bagValue = obj;
@@ -26,8 +28,8 @@
     }
 
     public SafeBag(
-        DERObjectIdentifier     oid,
-        DERObject               obj,
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable obj,
         ASN1Set                 bagAttributes)
     {
         this.bagId = oid;
@@ -35,23 +37,39 @@
         this.bagAttributes = bagAttributes;
     }
 
-    public SafeBag(
+    public static SafeBag getInstance(
+        Object  obj)
+    {
+        if (obj instanceof SafeBag)
+        {
+            return (SafeBag)obj;
+        }
+
+        if (obj != null)
+        {
+            return new SafeBag(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private SafeBag(
         ASN1Sequence    seq)
     {
-        this.bagId = (DERObjectIdentifier)seq.getObjectAt(0);
-        this.bagValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+        this.bagId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        this.bagValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject();
         if (seq.size() == 3)
         {
             this.bagAttributes = (ASN1Set)seq.getObjectAt(2);
         }
     }
 
-    public DERObjectIdentifier getBagId()
+    public ASN1ObjectIdentifier getBagId()
     {
         return bagId;
     }
 
-    public DERObject getBagValue()
+    public ASN1Encodable getBagValue()
     {
         return bagValue;
     }
@@ -61,18 +79,18 @@
         return bagAttributes;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
         v.add(bagId);
-        v.add(new DERTaggedObject(0, bagValue));
+        v.add(new DLTaggedObject(true, 0, bagValue));
 
         if (bagAttributes != null)
         {
             v.add(bagAttributes);
         }
 
-        return new DERSequence(v);
+        return new DLSequence(v);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java b/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
index 136ad11..234eb2e 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
@@ -2,23 +2,23 @@
 
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.ASN1Set;
 import org.bouncycastle.asn1.BERSequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERTaggedObject;
 
 /**
  * a PKCS#7 signed data object.
  */
 public class SignedData
-    extends ASN1Encodable
+    extends ASN1Object
     implements PKCSObjectIdentifiers
 {
-    private DERInteger              version;
+    private ASN1Integer              version;
     private ASN1Set                 digestAlgorithms;
     private ContentInfo             contentInfo;
     private ASN1Set                 certificates;
@@ -32,16 +32,16 @@
         {
             return (SignedData)o;
         }
-        else if (o instanceof ASN1Sequence)
+        else if (o != null)
         {
-            return new SignedData((ASN1Sequence)o);
+            return new SignedData(ASN1Sequence.getInstance(o));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + o);
+        return null;
     }
 
     public SignedData(
-        DERInteger        _version,
+        ASN1Integer        _version,
         ASN1Set           _digestAlgorithms,
         ContentInfo       _contentInfo,
         ASN1Set           _certificates,
@@ -61,13 +61,13 @@
     {
         Enumeration     e = seq.getObjects();
 
-        version = (DERInteger)e.nextElement();
+        version = (ASN1Integer)e.nextElement();
         digestAlgorithms = ((ASN1Set)e.nextElement());
         contentInfo = ContentInfo.getInstance(e.nextElement());
 
         while (e.hasMoreElements())
         {
-            DERObject o = (DERObject)e.nextElement();
+            ASN1Primitive o = (ASN1Primitive)e.nextElement();
 
             //
             // an interesting feature of SignedData is that there appear to be varying implementations...
@@ -96,7 +96,7 @@
         }
     }
 
-    public DERInteger getVersion()
+    public ASN1Integer getVersion()
     {
         return version;
     }
@@ -141,7 +141,7 @@
      *      signerInfos SignerInfos }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
new file mode 100644
index 0000000..4bf6b2b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
@@ -0,0 +1,143 @@
+package org.bouncycastle.asn1.sec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+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.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * the elliptic curve private key object from SEC 1
+ */
+public class ECPrivateKey
+    extends ASN1Object
+{
+    private ASN1Sequence seq;
+
+    private ECPrivateKey(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+    }
+
+    public static ECPrivateKey getInstance(
+        Object obj)
+    {
+        if (obj instanceof ECPrivateKey)
+        {
+            return (ECPrivateKey)obj;
+        }
+
+        if (obj != null)
+        {
+            return new ECPrivateKey(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ECPrivateKey(
+        BigInteger key)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(1));
+        v.add(new DEROctetString(bytes));
+
+        seq = new DERSequence(v);
+    }
+
+    public ECPrivateKey(
+        BigInteger key,
+        ASN1Object parameters)
+    {
+        this(key, null, parameters);
+    }
+
+    public ECPrivateKey(
+        BigInteger key,
+        DERBitString publicKey,
+        ASN1Object parameters)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(1));
+        v.add(new DEROctetString(bytes));
+
+        if (parameters != null)
+        {
+            v.add(new DERTaggedObject(true, 0, parameters));
+        }
+
+        if (publicKey != null)
+        {
+            v.add(new DERTaggedObject(true, 1, publicKey));
+        }
+
+        seq = new DERSequence(v);
+    }
+
+    public BigInteger getKey()
+    {
+        ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1);
+
+        return new BigInteger(1, octs.getOctets());
+    }
+
+    public DERBitString getPublicKey()
+    {
+        return (DERBitString)getObjectInTag(1);
+    }
+
+    public ASN1Primitive getParameters()
+    {
+        return getObjectInTag(0);
+    }
+
+    private ASN1Primitive getObjectInTag(int tagNo)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Encodable obj = (ASN1Encodable)e.nextElement();
+
+            if (obj instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+                if (tag.getTagNo() == tagNo)
+                {
+                    return tag.getObject().toASN1Primitive();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * ECPrivateKey ::= SEQUENCE {
+     *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+     *     privateKey OCTET STRING,
+     *     parameters [0] Parameters OPTIONAL,
+     *     publicKey [1] BIT STRING OPTIONAL }
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
index b9a0407..3b1bcc3 100644
--- a/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
@@ -5,14 +5,13 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 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.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
@@ -20,9 +19,10 @@
 
 /**
  * the elliptic curve private key object from SEC 1
+ * @deprecated use ECPrivateKey
  */
 public class ECPrivateKeyStructure
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private ASN1Sequence  seq;
 
@@ -39,7 +39,7 @@
 
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(1));
+        v.add(new ASN1Integer(1));
         v.add(new DEROctetString(bytes));
 
         seq = new DERSequence(v);
@@ -61,7 +61,7 @@
 
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(1));
+        v.add(new ASN1Integer(1));
         v.add(new DEROctetString(bytes));
 
         if (parameters != null)
@@ -89,25 +89,25 @@
         return (DERBitString)getObjectInTag(1);
     }
 
-    public ASN1Object getParameters()
+    public ASN1Primitive getParameters()
     {
         return getObjectInTag(0);
     }
 
-    private ASN1Object getObjectInTag(int tagNo)
+    private ASN1Primitive getObjectInTag(int tagNo)
     {
         Enumeration e = seq.getObjects();
 
         while (e.hasMoreElements())
         {
-            DEREncodable obj = (DEREncodable)e.nextElement();
+            ASN1Encodable obj = (ASN1Encodable)e.nextElement();
 
             if (obj instanceof ASN1TaggedObject)
             {
                 ASN1TaggedObject tag = (ASN1TaggedObject)obj;
                 if (tag.getTagNo() == tagNo)
                 {
-                    return (ASN1Object)((DEREncodable)tag.getObject()).getDERObject();
+                    return (ASN1Primitive)((ASN1Encodable)tag.getObject()).toASN1Primitive();
                 }
             }
         }
@@ -121,7 +121,7 @@
      *     parameters [0] Parameters OPTIONAL,
      *     publicKey [1] BIT STRING OPTIONAL }
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return seq;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
index 67ead06..44c811b 100644
--- a/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
+++ b/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -1,18 +1,18 @@
 package org.bouncycastle.asn1.sec;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.x9.X9ECParameters;
-import org.bouncycastle.asn1.x9.X9ECParametersHolder;
-import org.bouncycastle.math.ec.ECCurve;
-import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.math.ec.ECConstants;
-import org.bouncycastle.util.Strings;
-import org.bouncycastle.util.encoders.Hex;
-
 import java.math.BigInteger;
 import java.util.Enumeration;
 import java.util.Hashtable;
 
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
 public class SECNamedCurves
 {
     private static BigInteger fromHex(
@@ -920,7 +920,7 @@
     static final Hashtable curves = new Hashtable();
     static final Hashtable names = new Hashtable();
 
-    static void defineCurve(String name, DERObjectIdentifier oid, X9ECParametersHolder holder)
+    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
     {
         objIds.put(name, oid);
         names.put(oid, name);
@@ -968,7 +968,7 @@
     public static X9ECParameters getByName(
         String name)
     {
-        DERObjectIdentifier oid = (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
 
         if (oid != null)
         {
@@ -985,7 +985,7 @@
      * @param oid an object identifier representing a named curve, if present.
      */
     public static X9ECParameters getByOID(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
 
@@ -1003,17 +1003,17 @@
      *
      * @return the object identifier associated with name, if present.
      */
-    public static DERObjectIdentifier getOID(
+    public static ASN1ObjectIdentifier getOID(
         String name)
     {
-        return (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
     }
 
     /**
      * return the named curve name represented by the given object identifier.
      */
     public static String getName(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         return (String)names.get(oid);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
index 272f374..976f556 100644
--- a/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
+++ b/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -3,7 +3,11 @@
 import java.io.IOException;
 import java.util.Enumeration;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.BERApplicationSpecific;
@@ -11,29 +15,24 @@
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERSet;
 import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.BERTags;
 import org.bouncycastle.asn1.DERApplicationSpecific;
 import org.bouncycastle.asn1.DERBMPString;
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DERBoolean;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DEREnumerated;
 import org.bouncycastle.asn1.DERExternal;
 import org.bouncycastle.asn1.DERGeneralizedTime;
 import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERPrintableString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
 import org.bouncycastle.asn1.DERT61String;
 import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.DERTags;
 import org.bouncycastle.asn1.DERUTCTime;
 import org.bouncycastle.asn1.DERUTF8String;
-import org.bouncycastle.asn1.DERUnknownTag;
 import org.bouncycastle.asn1.DERVisibleString;
 import org.bouncycastle.util.encoders.Hex;
 
@@ -45,12 +44,12 @@
     /**
      * dump a DER object as a formatted string with indentation
      *
-     * @param obj the DERObject to be dumped out.
+     * @param obj the ASN1Primitive to be dumped out.
      */
     static void _dumpAsString(
         String      indent,
         boolean     verbose,
-        DERObject   obj,
+        ASN1Primitive obj,
         StringBuffer    buf)
     {
         String nl = System.getProperty("line.separator");
@@ -87,13 +86,13 @@
                     buf.append("NULL");
                     buf.append(nl);
                 }
-                else if (o instanceof DERObject)
+                else if (o instanceof ASN1Primitive)
                 {
-                    _dumpAsString(tab, verbose, (DERObject)o, buf);
+                    _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
                 }
                 else
                 {
-                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
+                    _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
                 }
             }
         }
@@ -153,13 +152,13 @@
                     buf.append("NULL");
                     buf.append(nl);
                 }
-                else if (o instanceof DERObject)
+                else if (o instanceof ASN1Primitive)
                 {
-                    _dumpAsString(tab, verbose, (DERObject)o, buf);
+                    _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
                 }
                 else
                 {
-                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
+                    _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
                 }
             }
         }
@@ -182,27 +181,27 @@
                     buf.append("NULL");
                     buf.append(nl);
                 }
-                else if (o instanceof DERObject)
+                else if (o instanceof ASN1Primitive)
                 {
-                    _dumpAsString(tab, verbose, (DERObject)o, buf);
+                    _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
                 }
                 else
                 {
-                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
+                    _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
                 }
             }
         }
-        else if (obj instanceof DERObjectIdentifier)
+        else if (obj instanceof ASN1ObjectIdentifier)
         {
-            buf.append(indent + "ObjectIdentifier(" + ((DERObjectIdentifier)obj).getId() + ")" + nl);
+            buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
         }
         else if (obj instanceof DERBoolean)
         {
             buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl);
         }
-        else if (obj instanceof DERInteger)
+        else if (obj instanceof ASN1Integer)
         {
-            buf.append(indent + "Integer(" + ((DERInteger)obj).getValue() + ")" + nl);
+            buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl);
         }
         else if (obj instanceof BERConstructedOctetString)
         {
@@ -272,10 +271,6 @@
         {
             buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl);
         }
-        else if (obj instanceof DERUnknownTag)
-        {
-            buf.append(indent + "Unknown " + Integer.toString(((DERUnknownTag)obj).getTag(), 16) + " " + new String(Hex.encode(((DERUnknownTag)obj).getData())) + nl);
-        }
         else if (obj instanceof BERApplicationSpecific)
         {
             buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl));
@@ -315,7 +310,7 @@
         }
     }
     
-    private static String outputApplicationSpecific(String type, String indent, boolean verbose, DERObject obj, String nl)
+    private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl)
     {
         DERApplicationSpecific app = (DERApplicationSpecific)obj;
         StringBuffer buf = new StringBuffer();
@@ -324,11 +319,11 @@
         {
             try
             {
-                ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(DERTags.SEQUENCE));
+                ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(BERTags.SEQUENCE));
                 buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
                 for (Enumeration e = s.getObjects(); e.hasMoreElements();)
                 {
-                    _dumpAsString(indent + TAB, verbose, (DERObject)e.nextElement(), buf);
+                    _dumpAsString(indent + TAB, verbose, (ASN1Primitive)e.nextElement(), buf);
                 }
             }
             catch (IOException e)
@@ -344,7 +339,7 @@
     /**
      * dump out a DER object as a formatted string, in non-verbose mode.
      *
-     * @param obj the DERObject to be dumped out.
+     * @param obj the ASN1Primitive to be dumped out.
      * @return  the resulting string.
      */
     public static String dumpAsString(
@@ -366,13 +361,13 @@
     {
         StringBuffer buf = new StringBuffer();
 
-        if (obj instanceof DERObject)
+        if (obj instanceof ASN1Primitive)
         {
-            _dumpAsString("", verbose, (DERObject)obj, buf);
+            _dumpAsString("", verbose, (ASN1Primitive)obj, buf);
         }
-        else if (obj instanceof DEREncodable)
+        else if (obj instanceof ASN1Encodable)
         {
-            _dumpAsString("", verbose, ((DEREncodable)obj).getDERObject(), buf);
+            _dumpAsString("", verbose, ((ASN1Encodable)obj).toASN1Primitive(), buf);
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
index bbe2171..7f283f9 100644
--- a/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
+++ b/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
@@ -2,13 +2,14 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class AttributeTypeAndValue
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private ASN1ObjectIdentifier type;
     private ASN1Encodable       value;
@@ -59,7 +60,7 @@
      * </pre>
      * @return a basic ASN.1 object representation.
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java b/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
index b76155c..cf7563e 100644
--- a/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
+++ b/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
@@ -2,25 +2,25 @@
 
 import org.bouncycastle.asn1.ASN1Choice;
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1String;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBMPString;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERPrintableString;
 import org.bouncycastle.asn1.DERT61String;
 import org.bouncycastle.asn1.DERUTF8String;
 import org.bouncycastle.asn1.DERUniversalString;
 
 public class DirectoryString
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice, ASN1String
 {
     private ASN1String string;
 
     public static DirectoryString getInstance(Object o)
     {
-        if (o instanceof DirectoryString)
+        if (o == null || o instanceof DirectoryString)
         {
             return (DirectoryString)o;
         }
@@ -118,8 +118,8 @@
      *    bmpString                   BMPString (SIZE (1..MAX))  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        return ((DEREncodable)string).getDERObject();
+        return ((ASN1Encodable)string).toASN1Primitive();
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x500/RDN.java b/src/main/java/org/bouncycastle/asn1/x500/RDN.java
index 700a918..f51c261 100644
--- a/src/main/java/org/bouncycastle/asn1/x500/RDN.java
+++ b/src/main/java/org/bouncycastle/asn1/x500/RDN.java
@@ -2,14 +2,15 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
 
 public class RDN
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private ASN1Set values;
 
@@ -35,8 +36,8 @@
     /**
      * Create a single valued RDN.
      *
-     * @param oid
-     * @param value
+     * @param oid RDN type.
+     * @param value RDN value.
      */
     public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
     {
@@ -55,6 +56,8 @@
 
     /**
      * Create a multi-valued RDN.
+     *
+     * @param aAndVs attribute type/value pairs making up the RDN
      */
     public RDN(AttributeTypeAndValue[] aAndVs)
     {
@@ -66,6 +69,16 @@
         return this.values.size() > 1;
     }
 
+    /**
+     * Return the number of AttributeTypeAndValue objects in this RDN,
+     *
+     * @return size of RDN, greater than 1 if multi-valued.
+     */
+    public int size()
+    {
+        return this.values.size();
+    }
+
     public AttributeTypeAndValue getFirst()
     {
         if (this.values.size() == 0)
@@ -97,9 +110,9 @@
      *        type     AttributeType,
      *        value    AttributeValue }
      * </pre>
-     * @return
+     * @return this object as an ASN1Primitive type
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return values;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x500/X500Name.java b/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
index 3166463..50e57c5 100644
--- a/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
+++ b/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
@@ -4,14 +4,13 @@
 
 import org.bouncycastle.asn1.ASN1Choice;
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x500.style.BCStyle;
-import org.bouncycastle.asn1.x509.X509Name;
 
 /**
  * <pre>
@@ -28,7 +27,7 @@
  * </pre>
  */
 public class X500Name
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice
 {
     private static X500NameStyle    defaultStyle = BCStyle.INSTANCE;
@@ -46,11 +45,11 @@
     }
 
     /**
-     * Return a X509Name based on the passed in tagged object.
+     * Return a X500Name based on the passed in tagged object.
      * 
      * @param obj tag object holding name.
      * @param explicit true if explicitly tagged false otherwise.
-     * @return the X509Name
+     * @return the X500Name
      */
     public static X500Name getInstance(
         ASN1TaggedObject obj,
@@ -67,10 +66,6 @@
         {
             return (X500Name)obj;
         }
-        else if (obj instanceof X509Name)
-        {
-            return new X500Name(ASN1Sequence.getInstance(((X509Name)obj).getDERObject()));
-        }
         else if (obj != null)
         {
             return new X500Name(ASN1Sequence.getInstance(obj));
@@ -79,6 +74,22 @@
         return null;
     }
 
+    public static X500Name getInstance(
+        X500NameStyle style,
+        Object        obj)
+    {
+        if (obj instanceof X500Name)
+        {
+            return getInstance(style, ((X500Name)obj).toASN1Primitive());
+        }
+        else if (obj != null)
+        {
+            return new X500Name(style, ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
     /**
      * Constructor from ASN1Sequence
      *
@@ -149,12 +160,53 @@
     }
 
     /**
+     * return an array of OIDs contained in the attribute type of each RDN in structure order.
+     *
+     * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects.
+     */
+    public ASN1ObjectIdentifier[] getAttributeTypes()
+    {
+        int   count = 0;
+
+        for (int i = 0; i != rdns.length; i++)
+        {
+            RDN rdn = rdns[i];
+
+            count += rdn.size();
+        }
+
+        ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count];
+
+        count = 0;
+
+        for (int i = 0; i != rdns.length; i++)
+        {
+            RDN rdn = rdns[i];
+
+            if (rdn.isMultiValued())
+            {
+                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
+                for (int j = 0; j != attr.length; j++)
+                {
+                    res[count++] = attr[j].getType();
+                }
+            }
+            else if (rdn.size() != 0)
+            {
+                res[count++] = rdn.getFirst().getType();
+            }
+        }
+
+        return res;
+    }
+
+    /**
      * return an array of RDNs containing the attribute type given by OID in structure order.
      *
-     * @param oid the type OID we are looking for.
+     * @param attributeType the type OID we are looking for.
      * @return an array, possibly zero length, of RDN objects.
      */
-    public RDN[] getRDNs(ASN1ObjectIdentifier oid)
+    public RDN[] getRDNs(ASN1ObjectIdentifier attributeType)
     {
         RDN[] res = new RDN[rdns.length];
         int   count = 0;
@@ -168,7 +220,7 @@
                 AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
                 for (int j = 0; j != attr.length; j++)
                 {
-                    if (attr[j].getType().equals(oid))
+                    if (attr[j].getType().equals(attributeType))
                     {
                         res[count++] = rdn;
                         break;
@@ -177,7 +229,7 @@
             }
             else
             {
-                if (rdn.getFirst().getType().equals(oid))
+                if (rdn.getFirst().getType().equals(attributeType))
                 {
                     res[count++] = rdn;
                 }
@@ -191,7 +243,7 @@
         return tmp;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return new DERSequence(rdns);
     }
@@ -225,16 +277,16 @@
             return false;
         }
         
-        DERObject derO = ((DEREncodable)obj).getDERObject();
+        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
 
-        if (this.getDERObject().equals(derO))
+        if (this.toASN1Primitive().equals(derO))
         {
             return true;
         }
 
         try
         {
-            return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((DEREncodable)obj).getDERObject())));
+            return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive())));
         }
         catch (Exception e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
index 5803042..5c60c89 100644
--- a/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
+++ b/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -5,10 +5,10 @@
 import java.util.Vector;
 
 import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1String;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERUniversalString;
 import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
 import org.bouncycastle.asn1.x500.RDN;
@@ -148,7 +148,7 @@
             }
         }
 
-        return ASN1Object.fromByteArray(data);
+        return ASN1Primitive.fromByteArray(data);
     }
 
     public static void appendTypeAndValue(
@@ -190,7 +190,14 @@
         }
         else
         {
-            vBuf.append("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
+            try
+            {
+                vBuf.append("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("Other value has no encoded form");
+            }
         }
 
         int     end = vBuf.length();
@@ -242,7 +249,7 @@
 
         if (value.length() > 0 && value.charAt(0) == '#')
         {
-            DERObject obj = decodeObject(value);
+            ASN1Primitive obj = decodeObject(value);
 
             if (obj instanceof ASN1String)
             {
@@ -255,11 +262,11 @@
         return value;
     }
 
-    private static ASN1Object decodeObject(String oValue)
+    private static ASN1Primitive decodeObject(String oValue)
     {
         try
         {
-            return ASN1Object.fromByteArray(Hex.decode(oValue.substring(1)));
+            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
index 7288d38..6f7c3be 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -2,20 +2,21 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1SequenceParser;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
 public class AlgorithmIdentifier
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERObjectIdentifier objectId;
-    private DEREncodable        parameters;
+    private ASN1ObjectIdentifier objectId;
+    private ASN1Encodable       parameters;
     private boolean             parametersDefined = false;
 
     public static AlgorithmIdentifier getInstance(
@@ -33,9 +34,9 @@
             return (AlgorithmIdentifier)obj;
         }
         
-        if (obj instanceof DERObjectIdentifier)
+        if (obj instanceof ASN1ObjectIdentifier)
         {
-            return new AlgorithmIdentifier((DERObjectIdentifier)obj);
+            return new AlgorithmIdentifier((ASN1ObjectIdentifier)obj);
         }
 
         if (obj instanceof String)
@@ -43,29 +44,57 @@
             return new AlgorithmIdentifier((String)obj);
         }
 
-        if (obj instanceof ASN1Sequence)
+        if (obj instanceof ASN1Sequence || obj instanceof ASN1SequenceParser)
         {
-            return new AlgorithmIdentifier((ASN1Sequence)obj);
+            return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj));
         }
 
         throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
     }
 
     public AlgorithmIdentifier(
-        DERObjectIdentifier     objectId)
+        ASN1ObjectIdentifier     objectId)
     {
         this.objectId = objectId;
     }
 
+    /**
+     * @deprecated use ASN1ObjectIdentifier
+     * @param objectId
+     */
     public AlgorithmIdentifier(
         String     objectId)
     {
-        this.objectId = new DERObjectIdentifier(objectId);
+        this.objectId = new ASN1ObjectIdentifier(objectId);
+    }
+
+    /**
+     * @deprecated use ASN1ObjectIdentifier
+     * @param objectId
+     */
+    public AlgorithmIdentifier(
+        DERObjectIdentifier    objectId)
+    {
+        this.objectId = new ASN1ObjectIdentifier(objectId.getId());
+    }
+
+    /**
+     * @deprecated use ASN1ObjectIdentifier
+     * @param objectId
+     * @param parameters
+     */
+    public AlgorithmIdentifier(
+        DERObjectIdentifier objectId,
+        ASN1Encodable           parameters)
+    {
+        parametersDefined = true;
+        this.objectId = new ASN1ObjectIdentifier(objectId.getId());
+        this.parameters = parameters;
     }
 
     public AlgorithmIdentifier(
-        DERObjectIdentifier     objectId,
-        DEREncodable            parameters)
+        ASN1ObjectIdentifier     objectId,
+        ASN1Encodable           parameters)
     {
         parametersDefined = true;
         this.objectId = objectId;
@@ -81,7 +110,7 @@
                     + seq.size());
         }
         
-        objectId = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+        objectId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
 
         if (seq.size() == 2)
         {
@@ -103,12 +132,12 @@
      * @deprecated use getAlgorithm
      * @return
      */
-    public DERObjectIdentifier getObjectId()
+    public ASN1ObjectIdentifier getObjectId()
     {
         return objectId;
     }
 
-    public DEREncodable getParameters()
+    public ASN1Encodable getParameters()
     {
         return parameters;
     }
@@ -121,7 +150,7 @@
      *                            parameters ANY DEFINED BY algorithm OPTIONAL }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java b/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
index 2d67a51..21907c6 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
@@ -2,22 +2,23 @@
 
 import org.bouncycastle.asn1.ASN1Choice;
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERTaggedObject;
 
 public class AttCertIssuer
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice
 {
     ASN1Encodable   obj;
-    DERObject       choiceObj;
+    ASN1Primitive choiceObj;
     
     public static AttCertIssuer getInstance(
         Object  obj)
     {
-        if (obj instanceof AttCertIssuer)
+        if (obj == null || obj instanceof AttCertIssuer)
         {
             return (AttCertIssuer)obj;
         }
@@ -58,7 +59,7 @@
         GeneralNames  names)
     {
         obj = names;
-        choiceObj = obj.getDERObject();
+        choiceObj = obj.toASN1Primitive();
     }
     
     public AttCertIssuer(
@@ -83,7 +84,7 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return choiceObj;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java b/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
index a4ab4cd..e157b66 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
@@ -1,14 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERGeneralizedTime;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class AttCertValidityPeriod
-    extends ASN1Encodable
+    extends ASN1Object
 {
     DERGeneralizedTime  notBeforeTime;
     DERGeneralizedTime  notAfterTime;
@@ -20,15 +20,15 @@
         {
             return (AttCertValidityPeriod)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new AttCertValidityPeriod((ASN1Sequence)obj);
+            return new AttCertValidityPeriod(ASN1Sequence.getInstance(obj));
         }
         
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
-    public AttCertValidityPeriod(
+    private AttCertValidityPeriod(
         ASN1Sequence    seq)
     {
         if (seq.size() != 2)
@@ -72,7 +72,7 @@
      *  } 
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Attribute.java b/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
index 56df178..b8d4bde 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
@@ -2,17 +2,17 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
 public class Attribute
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERObjectIdentifier attrType;
+    private ASN1ObjectIdentifier attrType;
     private ASN1Set             attrValues;
 
     /**
@@ -24,20 +24,20 @@
     public static Attribute getInstance(
         Object o)
     {
-        if (o == null || o instanceof Attribute)
+        if (o instanceof Attribute)
         {
             return (Attribute)o;
         }
         
-        if (o instanceof ASN1Sequence)
+        if (o != null)
         {
-            return new Attribute((ASN1Sequence)o);
+            return new Attribute(ASN1Sequence.getInstance(o));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName());
+        return null;
     }
     
-    public Attribute(
+    private Attribute(
         ASN1Sequence seq)
     {
         if (seq.size() != 2)
@@ -45,12 +45,12 @@
             throw new IllegalArgumentException("Bad sequence size: " + seq.size());
         }
 
-        attrType = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+        attrType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
         attrValues = ASN1Set.getInstance(seq.getObjectAt(1));
     }
 
     public Attribute(
-        DERObjectIdentifier attrType,
+        ASN1ObjectIdentifier attrType,
         ASN1Set             attrValues)
     {
         this.attrType = attrType;
@@ -81,7 +81,7 @@
      * }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
index 9e79e89..92aa0f7 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -1,14 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class AttributeCertificate
-    extends ASN1Encodable
+    extends ASN1Object
 {
     AttributeCertificateInfo    acinfo;
     AlgorithmIdentifier         signatureAlgorithm;
@@ -81,7 +81,7 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
index 59ff27a..7b9d450 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
@@ -2,25 +2,26 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 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.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class AttributeCertificateInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERInteger              version;
+    private ASN1Integer              version;
     private Holder                  holder;
     private AttCertIssuer           issuer;
     private AlgorithmIdentifier     signature;
-    private DERInteger              serialNumber;
+    private ASN1Integer              serialNumber;
     private AttCertValidityPeriod   attrCertValidityPeriod;
     private ASN1Sequence            attributes;
     private DERBitString            issuerUniqueID;
-    private X509Extensions          extensions;
+    private Extensions              extensions;
 
     public static AttributeCertificateInfo getInstance(
         ASN1TaggedObject obj,
@@ -36,15 +37,15 @@
         {
             return (AttributeCertificateInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new AttributeCertificateInfo((ASN1Sequence)obj);
+            return new AttributeCertificateInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
-    public AttributeCertificateInfo(
+    private AttributeCertificateInfo(
         ASN1Sequence   seq)
     {
         if (seq.size() < 7 || seq.size() > 9)
@@ -52,11 +53,11 @@
             throw new IllegalArgumentException("Bad sequence size: " + seq.size());
         }
 
-        this.version = DERInteger.getInstance(seq.getObjectAt(0));
+        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 = DERInteger.getInstance(seq.getObjectAt(4));
+        this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4));
         this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5));
         this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6));
         
@@ -68,14 +69,14 @@
             {
                 this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i));
             }
-            else if (obj instanceof ASN1Sequence || obj instanceof X509Extensions)
+            else if (obj instanceof ASN1Sequence || obj instanceof Extensions)
             {
-                this.extensions = X509Extensions.getInstance(seq.getObjectAt(i));
+                this.extensions = Extensions.getInstance(seq.getObjectAt(i));
             }
         }
     }
     
-    public DERInteger getVersion()
+    public ASN1Integer getVersion()
     {
         return version;
     }
@@ -95,7 +96,7 @@
         return signature;
     }
 
-    public DERInteger getSerialNumber()
+    public ASN1Integer getSerialNumber()
     {
         return serialNumber;
     }
@@ -115,7 +116,7 @@
         return issuerUniqueID;
     }
 
-    public X509Extensions getExtensions()
+    public Extensions getExtensions()
     {
         return extensions;
     }
@@ -138,7 +139,7 @@
      *  AttCertVersion ::= INTEGER { v2(1) }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
index a3e5a54..9a73dd6 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
@@ -1,20 +1,22 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
 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.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-
-import java.math.BigInteger;
-import java.util.Enumeration;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 
 /**
  * The AuthorityKeyIdentifier object.
@@ -31,11 +33,11 @@
  *
  */
 public class AuthorityKeyIdentifier
-    extends ASN1Encodable
+    extends ASN1Object
 {
     ASN1OctetString keyidentifier=null;
     GeneralNames certissuer=null;
-    DERInteger certserno=null;
+    ASN1Integer certserno=null;
 
     public static AuthorityKeyIdentifier getInstance(
         ASN1TaggedObject obj,
@@ -51,19 +53,15 @@
         {
             return (AuthorityKeyIdentifier)obj;
         }
-        if (obj instanceof ASN1Sequence)
+        if (obj != null)
         {
-            return new AuthorityKeyIdentifier((ASN1Sequence)obj);
-        }
-        if (obj instanceof X509Extension)
-        {
-            return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
+            return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
-    public AuthorityKeyIdentifier(
+    protected AuthorityKeyIdentifier(
         ASN1Sequence   seq)
     {
         Enumeration     e = seq.getObjects();
@@ -81,7 +79,7 @@
                 this.certissuer = GeneralNames.getInstance(o, false);
                 break;
             case 2:
-                this.certserno = DERInteger.getInstance(o, false);
+                this.certserno = ASN1Integer.getInstance(o, false);
                 break;
             default:
                 throw new IllegalArgumentException("illegal tag");
@@ -105,7 +103,9 @@
     public AuthorityKeyIdentifier(
         SubjectPublicKeyInfo    spki)
     {
-        Digest  digest = new SHA1Digest();
+        // BEGIN android-changed
+        Digest  digest = new OpenSSLDigest.SHA1();
+        // END android-changed
         byte[]  resBuf = new byte[digest.getDigestSize()];
 
         byte[] bytes = spki.getPublicKeyData().getBytes();
@@ -123,7 +123,9 @@
         GeneralNames            name,
         BigInteger              serialNumber)
     {
-        Digest  digest = new SHA1Digest();
+        // BEGIN android-changed
+        Digest  digest = new OpenSSLDigest.SHA1();
+        // END android-changed
         byte[]  resBuf = new byte[digest.getDigestSize()];
 
         byte[] bytes = spki.getPublicKeyData().getBytes();
@@ -131,8 +133,8 @@
         digest.doFinal(resBuf, 0);
 
         this.keyidentifier = new DEROctetString(resBuf);
-        this.certissuer = GeneralNames.getInstance(name.toASN1Object());
-        this.certserno = new DERInteger(serialNumber);
+        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+        this.certserno = new ASN1Integer(serialNumber);
     }
 
     /**
@@ -144,8 +146,8 @@
         BigInteger              serialNumber)
     {
         this.keyidentifier = null;
-        this.certissuer = GeneralNames.getInstance(name.toASN1Object());
-        this.certserno = new DERInteger(serialNumber);
+        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+        this.certserno = new ASN1Integer(serialNumber);
     }
 
     /**
@@ -169,8 +171,8 @@
         BigInteger              serialNumber)
     {
         this.keyidentifier = new DEROctetString(keyIdentifier);
-        this.certissuer = GeneralNames.getInstance(name.toASN1Object());
-        this.certserno = new DERInteger(serialNumber);
+        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+        this.certserno = new ASN1Integer(serialNumber);
     }
     
     public byte[] getKeyIdentifier()
@@ -201,7 +203,7 @@
     /**
      * Produce an object suitable for an ASN1OutputStream.
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
index 08a0c04..19fa762 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
@@ -1,23 +1,23 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+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.DERBoolean;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
-import java.math.BigInteger;
-
 public class BasicConstraints
-    extends ASN1Encodable
+    extends ASN1Object
 {
     // BEGIN android-changed
     DERBoolean  cA = DERBoolean.FALSE;
     // END android-changed
-    DERInteger  pathLenConstraint = null;
+    ASN1Integer  pathLenConstraint = null;
 
     public static BasicConstraints getInstance(
         ASN1TaggedObject obj,
@@ -29,25 +29,23 @@
     public static BasicConstraints getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof BasicConstraints)
+        if (obj instanceof BasicConstraints)
         {
             return (BasicConstraints)obj;
         }
-
-        if (obj instanceof ASN1Sequence)
-        {
-            return new BasicConstraints((ASN1Sequence)obj);
-        }
-
         if (obj instanceof X509Extension)
         {
             return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
         }
+        if (obj != null)
+        {
+            return new BasicConstraints(ASN1Sequence.getInstance(obj));
+        }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
-    public BasicConstraints(
+    private BasicConstraints(
         ASN1Sequence   seq)
     {
         if (seq.size() == 0)
@@ -64,13 +62,13 @@
             else
             {
                 this.cA = null;
-                this.pathLenConstraint = DERInteger.getInstance(seq.getObjectAt(0));
+                this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0));
             }
             if (seq.size() > 1)
             {
                 if (this.cA != null)
                 {
-                    this.pathLenConstraint = DERInteger.getInstance(seq.getObjectAt(1));
+                    this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1));
                 }
                 else
                 {
@@ -80,29 +78,6 @@
         }
     }
 
-    /**
-     * @deprecated use one of the other two unambigous constructors.
-     * @param cA
-     * @param pathLenConstraint
-     */
-    public BasicConstraints(
-        boolean cA,
-        int     pathLenConstraint)
-    {
-        if (cA)
-        {
-            // BEGIN android-changed
-            this.cA = DERBoolean.getInstance(cA);
-            // END android-changed
-            this.pathLenConstraint = new DERInteger(pathLenConstraint);
-        }
-        else
-        {
-            this.cA = null;
-            this.pathLenConstraint = null;
-        }
-    }
-
     public BasicConstraints(
         boolean cA)
     {
@@ -130,7 +105,7 @@
         // BEGIN android-changed
         this.cA = DERBoolean.TRUE;
         // END android-changed
-        this.pathLenConstraint = new DERInteger(pathLenConstraint);
+        this.pathLenConstraint = new ASN1Integer(pathLenConstraint);
     }
 
     public boolean isCA()
@@ -157,7 +132,7 @@
      * }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
index 67244b1..1ee6aa5 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
@@ -1,14 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class CRLDistPoint
-    extends ASN1Encodable
+    extends ASN1Object
 {
     ASN1Sequence  seq = null;
 
@@ -22,19 +22,19 @@
     public static CRLDistPoint getInstance(
         Object  obj)
     {
-        if (obj instanceof CRLDistPoint || obj == null)
+        if (obj instanceof CRLDistPoint)
         {
             return (CRLDistPoint)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new CRLDistPoint((ASN1Sequence)obj);
+            return new CRLDistPoint(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
-    public CRLDistPoint(
+    private CRLDistPoint(
         ASN1Sequence seq)
     {
         this.seq = seq;
@@ -76,7 +76,7 @@
      * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return seq;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java b/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
index 5c74abf..95425ba 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
@@ -1,9 +1,11 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.DERInteger;
-
 import java.math.BigInteger;
 
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+
 /**
  * The CRLNumber object.
  * <pre>
@@ -11,22 +13,42 @@
  * </pre>
  */
 public class CRLNumber
-    extends DERInteger
+    extends ASN1Object
 {
+    private BigInteger number;
 
     public CRLNumber(
         BigInteger number)
     {
-        super(number);
+        this.number = number;
     }
 
     public BigInteger getCRLNumber()
     {
-        return getPositiveValue();
+        return number;
     }
 
     public String toString()
     {
         return "CRLNumber: " + getCRLNumber();
     }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new ASN1Integer(number);
+    }
+
+    public static CRLNumber getInstance(Object o)
+    {
+        if (o instanceof CRLNumber)
+        {
+            return (CRLNumber)o;
+        }
+        else if (o != null)
+        {
+            return new CRLNumber(ASN1Integer.getInstance(o).getValue());
+        }
+
+        return null;
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java b/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
index dfbccda..621b5c8 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
@@ -1,6 +1,11 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.DEREnumerated;
+import java.math.BigInteger;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 
 /**
  * The CRLReason enumeration.
@@ -20,7 +25,7 @@
  * </pre>
  */
 public class CRLReason
-    extends DEREnumerated
+    extends ASN1Object
 {
     /**
      * @deprecated use lower case version
@@ -82,16 +87,28 @@
         "removeFromCRL", "privilegeWithdrawn", "aACompromise"
     };
 
-    public CRLReason(
-        int reason)
+    private static final Hashtable table = new Hashtable();
+
+    private ASN1Enumerated value;
+
+    public static CRLReason getInstance(Object o)
     {
-        super(reason);
+        if (o instanceof CRLReason)
+        {
+            return (CRLReason)o;
+        }
+        else if (o != null)
+        {
+            return lookup(ASN1Enumerated.getInstance(o).getValue().intValue());
+        }
+
+        return null;
     }
 
-    public CRLReason(
-        DEREnumerated reason)
+    private CRLReason(
+        int reason)
     {
-        super(reason.getValue().intValue());
+        value = new ASN1Enumerated(reason);
     }
 
     public String toString()
@@ -107,5 +124,29 @@
             str = reasonString[reason];
         }
         return "CRLReason: " + str;
-    }    
+    }
+
+    public BigInteger getValue()
+    {
+        return value.getValue();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return value;
+    }
+
+    public static CRLReason lookup(int value)
+    {
+        // BEGIN android-changed
+        Integer idx = Integer.valueOf(value);
+        // END android-changed
+
+        if (!table.containsKey(idx))
+        {
+            table.put(idx, new CRLReason(value));
+        }
+
+        return (CRLReason)table.get(idx);
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Certificate.java b/src/main/java/org/bouncycastle/asn1/x509/Certificate.java
new file mode 100644
index 0000000..4ca14d4
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x509/Certificate.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERBitString;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ *  Certificate ::= SEQUENCE {
+ *      tbsCertificate          TBSCertificate,
+ *      signatureAlgorithm      AlgorithmIdentifier,
+ *      signature               BIT STRING
+ *  }
+ * </pre>
+ */
+public class Certificate
+    extends ASN1Object
+{
+    ASN1Sequence  seq;
+    TBSCertificate tbsCert;
+    AlgorithmIdentifier     sigAlgId;
+    DERBitString            sig;
+
+    public static Certificate getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Certificate getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Certificate)
+        {
+            return (Certificate)obj;
+        }
+        else if (obj != null)
+        {
+            return new Certificate(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private Certificate(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+
+        //
+        // correct x509 certficate
+        //
+        if (seq.size() == 3)
+        {
+            tbsCert = TBSCertificate.getInstance(seq.getObjectAt(0));
+            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+
+            sig = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("sequence wrong size for a certificate");
+        }
+    }
+
+    public TBSCertificate getTBSCertificate()
+    {
+        return tbsCert;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return tbsCert.getVersion();
+    }
+
+    public int getVersionNumber()
+    {
+        return tbsCert.getVersionNumber();
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return tbsCert.getSerialNumber();
+    }
+
+    public X500Name getIssuer()
+    {
+        return tbsCert.getIssuer();
+    }
+
+    public Time getStartDate()
+    {
+        return tbsCert.getStartDate();
+    }
+
+    public Time getEndDate()
+    {
+        return tbsCert.getEndDate();
+    }
+
+    public X500Name getSubject()
+    {
+        return tbsCert.getSubject();
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return tbsCert.getSubjectPublicKeyInfo();
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sig;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
index 40c49c6..91a37ad 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
@@ -3,13 +3,14 @@
 
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
 
 /**
  * PKIX RFC-2459
@@ -25,7 +26,7 @@
  * </pre>
  */
 public class CertificateList
-    extends ASN1Encodable
+    extends ASN1Object
 {
     TBSCertList            tbsCertList;
     AlgorithmIdentifier    sigAlgId;
@@ -93,12 +94,12 @@
         return sig;
     }
 
-    public int getVersion()
+    public int getVersionNumber()
     {
-        return tbsCertList.getVersion();
+        return tbsCertList.getVersionNumber();
     }
 
-    public X509Name getIssuer()
+    public X500Name getIssuer()
     {
         return tbsCertList.getIssuer();
     }
@@ -113,7 +114,7 @@
         return tbsCertList.getNextUpdate();
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java b/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
index 50822d6..853bd35 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
@@ -3,18 +3,18 @@
 import java.math.BigInteger;
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class DSAParameter
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    DERInteger      p, q, g;
+    ASN1Integer      p, q, g;
 
     public static DSAParameter getInstance(
         ASN1TaggedObject obj,
@@ -44,9 +44,9 @@
         BigInteger  q,
         BigInteger  g)
     {
-        this.p = new DERInteger(p);
-        this.q = new DERInteger(q);
-        this.g = new DERInteger(g);
+        this.p = new ASN1Integer(p);
+        this.q = new ASN1Integer(q);
+        this.g = new ASN1Integer(g);
     }
 
     public DSAParameter(
@@ -59,9 +59,9 @@
         
         Enumeration     e = seq.getObjects();
 
-        p = DERInteger.getInstance(e.nextElement());
-        q = DERInteger.getInstance(e.nextElement());
-        g = DERInteger.getInstance(e.nextElement());
+        p = ASN1Integer.getInstance(e.nextElement());
+        q = ASN1Integer.getInstance(e.nextElement());
+        g = ASN1Integer.getInstance(e.nextElement());
     }
 
     public BigInteger getP()
@@ -79,7 +79,7 @@
         return g.getPositiveValue();
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java b/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
index baf93e1..fd17f1b 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
@@ -2,12 +2,12 @@
 
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
 
@@ -20,7 +20,7 @@
  * </pre>
  */
 public class DigestInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private byte[]                  digest;
     private AlgorithmIdentifier     algId;
@@ -39,12 +39,12 @@
         {
             return (DigestInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new DigestInfo((ASN1Sequence)obj);
+            return new DigestInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public DigestInfo(
@@ -74,7 +74,7 @@
         return digest;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
index e57c408..ab73dfb 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
@@ -1,11 +1,11 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
@@ -20,7 +20,7 @@
  * </pre>
  */
 public class DistributionPoint
-    extends ASN1Encodable
+    extends ASN1Object
 {
     DistributionPointName       distributionPoint;
     ReasonFlags                 reasons;
@@ -94,7 +94,7 @@
         return cRLIssuer;
     }
     
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
         
diff --git a/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
index b6a294e..ee06efd 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
@@ -2,10 +2,10 @@
 
 import org.bouncycastle.asn1.ASN1Choice;
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERTaggedObject;
 
 /**
@@ -18,10 +18,10 @@
  * </pre>
  */
 public class DistributionPointName
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice
 {
-    DEREncodable        name;
+    ASN1Encodable        name;
     int                 type;
 
     public static final int FULL_NAME = 0;
@@ -49,17 +49,6 @@
         throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
     }
 
-    /*
-     * @deprecated use ASN1Encodable
-     */
-    public DistributionPointName(
-        int             type,
-        DEREncodable    name)
-    {
-        this.type = type;
-        this.name = name;
-    }
-
     public DistributionPointName(
         int             type,
         ASN1Encodable   name)
@@ -109,7 +98,7 @@
         }
     }
     
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return new DERTaggedObject(false, type, name);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
index 0811df5..97f1c54 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
@@ -1,17 +1,17 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DERSequence;
-
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Vector;
 
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+
 /**
  * The extendedKeyUsage object.
  * <pre>
@@ -19,7 +19,7 @@
  * </pre>
  */
 public class ExtendedKeyUsage
-    extends ASN1Encodable
+    extends ASN1Object
 {
     Hashtable     usageTable = new Hashtable();
     ASN1Sequence  seq;
@@ -39,17 +39,12 @@
             return (ExtendedKeyUsage)obj;
         }
         
-        if(obj instanceof ASN1Sequence) 
+        if (obj != null)
         {
-            return new ExtendedKeyUsage((ASN1Sequence)obj);
+            return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj));
         }
 
-        if (obj instanceof X509Extension)
-        {
-            return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
-        }
-
-        throw new IllegalArgumentException("Invalid ExtendedKeyUsage: " + obj.getClass().getName());
+        return null;
     }
 
     public ExtendedKeyUsage(
@@ -70,9 +65,9 @@
         while (e.hasMoreElements())
         {
             Object  o = e.nextElement();
-            if (!(o instanceof DERObjectIdentifier))
+            if (!(o instanceof ASN1ObjectIdentifier))
             {
-                throw new IllegalArgumentException("Only DERObjectIdentifiers allowed in ExtendedKeyUsage.");
+                throw new IllegalArgumentException("Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage.");
             }
             this.usageTable.put(o, o);
         }
@@ -86,7 +81,7 @@
 
         while (e.hasMoreElements())
         {
-            DERObject  o = (DERObject)e.nextElement();
+            ASN1Primitive  o = (ASN1Primitive)e.nextElement();
 
             v.add(o);
             this.usageTable.put(o, o);
@@ -103,7 +98,7 @@
     
     /**
      * Returns all extended key usages.
-     * The returned vector contains DERObjectIdentifiers.
+     * The returned vector contains ASN1ObjectIdentifiers.
      * @return A vector with all key purposes.
      */
     public Vector getUsages()
@@ -121,7 +116,7 @@
         return usageTable.size();
     }
     
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return seq;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Extension.java b/src/main/java/org/bouncycastle/asn1/x509/Extension.java
new file mode 100644
index 0000000..e6a06d8
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x509/Extension.java
@@ -0,0 +1,266 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1Boolean;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DEROctetString;
+
+/**
+ * an object for the elements in the X.509 V3 extension block.
+ */
+public class Extension
+{
+    /**
+     * Subject Directory Attributes
+     */
+    public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
+    
+    /**
+     * Subject Key Identifier 
+     */
+    public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
+
+    /**
+     * Key Usage 
+     */
+    public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15");
+
+    /**
+     * Private Key Usage Period 
+     */
+    public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
+
+    /**
+     * Subject Alternative Name 
+     */
+    public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
+
+    /**
+     * Issuer Alternative Name 
+     */
+    public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
+
+    /**
+     * Basic Constraints 
+     */
+    public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
+
+    /**
+     * CRL Number 
+     */
+    public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
+
+    /**
+     * Reason code 
+     */
+    public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21");
+
+    /**
+     * Hold Instruction Code 
+     */
+    public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23");
+
+    /**
+     * Invalidity Date 
+     */
+    public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
+
+    /**
+     * Delta CRL indicator 
+     */
+    public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
+
+    /**
+     * Issuing Distribution Point 
+     */
+    public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
+
+    /**
+     * Certificate Issuer 
+     */
+    public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
+
+    /**
+     * Name Constraints 
+     */
+    public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
+
+    /**
+     * CRL Distribution Points 
+     */
+    public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
+
+    /**
+     * Certificate Policies 
+     */
+    public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
+
+    /**
+     * Policy Mappings 
+     */
+    public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33");
+
+    /**
+     * Authority Key Identifier 
+     */
+    public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
+
+    /**
+     * Policy Constraints 
+     */
+    public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
+
+    /**
+     * Extended Key Usage 
+     */
+    public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
+
+    /**
+     * Freshest CRL
+     */
+    public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
+     
+    /**
+     * Inhibit Any Policy
+     */
+    public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
+
+    /**
+     * Authority Info Access
+     */
+    public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+    /**
+     * Subject Info Access
+     */
+    public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11");
+    
+    /**
+     * Logo Type
+     */
+    public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+    /**
+     * BiometricInfo
+     */
+    public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
+    
+    /**
+     * QCStatements
+     */
+    public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+    /**
+     * Audit identity extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4");
+    
+    /**
+     * NoRevAvail extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
+
+    /**
+     * TargetInformation extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55");
+
+    private ASN1ObjectIdentifier extnId;
+
+    boolean             critical;
+    ASN1OctetString      value;
+
+    public Extension(
+        ASN1ObjectIdentifier extnId,
+        ASN1Boolean critical,
+        ASN1OctetString value)
+    {
+        this(extnId, critical.isTrue(), value);
+    }
+
+    public Extension(
+        ASN1ObjectIdentifier extnId,
+        boolean critical,
+        byte[] value)
+    {
+        this(extnId, critical, new DEROctetString(value));
+    }
+
+    public Extension(
+        ASN1ObjectIdentifier extnId,
+        boolean critical,
+        ASN1OctetString value)
+    {
+        this.extnId = extnId;
+        this.critical = critical;
+        this.value = value;
+    }
+
+    public ASN1ObjectIdentifier getExtnId()
+    {
+        return extnId;
+    }
+
+    public boolean isCritical()
+    {
+        return critical;
+    }
+
+    public ASN1OctetString getExtnValue()
+    {
+        return value;
+    }
+
+    public ASN1Encodable getParsedValue()
+    {
+        return convertValueToObject(this);
+    }
+
+    public int hashCode()
+    {
+        if (this.isCritical())
+        {
+            return this.getExtnValue().hashCode();
+        }
+
+        return ~this.getExtnValue().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof Extension))
+        {
+            return false;
+        }
+
+        Extension other = (Extension)o;
+
+        return other.getExtnValue().equals(this.getExtnValue())
+            && (other.isCritical() == this.isCritical());
+    }
+
+    /**
+     * Convert the value of the passed in extension to an object
+     * @param ext the extension to parse
+     * @return the object the value string contains
+     * @exception IllegalArgumentException if conversion is not possible
+     */
+    private static ASN1Primitive convertValueToObject(
+        Extension ext)
+        throws IllegalArgumentException
+    {
+        try
+        {
+            return ASN1Primitive.fromByteArray(ext.getExtnValue().getOctets());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't convert extension: " +  e);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Extensions.java b/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
new file mode 100644
index 0000000..1b93305
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
@@ -0,0 +1,214 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Boolean;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class Extensions
+    extends ASN1Object
+{
+    private Hashtable               extensions = new Hashtable();
+    private Vector                  ordering = new Vector();
+
+    public static Extensions getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Extensions getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Extensions)
+        {
+            return (Extensions)obj;
+        }
+        else if (obj != null)
+        {
+            return new Extensions(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructor from ASN1Sequence.
+     *
+     * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+     */
+    private Extensions(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Sequence            s = ASN1Sequence.getInstance(e.nextElement());
+
+            if (s.size() == 3)
+            {
+                extensions.put(s.getObjectAt(0), new Extension(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)), ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
+            }
+            else if (s.size() == 2)
+            {
+                extensions.put(s.getObjectAt(0), new Extension(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)), false, ASN1OctetString.getInstance(s.getObjectAt(1))));
+            }
+            else
+            {
+                throw new IllegalArgumentException("Bad sequence size: " + s.size());
+            }
+
+            ordering.addElement(s.getObjectAt(0));
+        }
+    }
+
+    /**
+     * Base Constructor
+     * 
+     * @param extensions an array of extensions.
+     */
+    public Extensions(
+        Extension[] extensions)
+    {
+        for (int i = 0; i != extensions.length; i++)
+        {
+            Extension ext = extensions[i];
+
+            this.ordering.addElement(ext.getExtnId());
+            this.extensions.put(ext.getExtnId(), ext);
+        }
+    }
+    
+    /**
+     * return an Enumeration of the extension field's object ids.
+     */
+    public Enumeration oids()
+    {
+        return ordering.elements();
+    }
+
+    /**
+     * return the extension represented by the object identifier
+     * passed in.
+     *
+     * @return the extension if it's present, null otherwise.
+     */
+    public Extension getExtension(
+        ASN1ObjectIdentifier oid)
+    {
+        return (Extension)extensions.get(oid);
+    }
+
+    /**
+     * <pre>
+     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+     *
+     *     Extension         ::=   SEQUENCE {
+     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+     *        critical          BOOLEAN DEFAULT FALSE,
+     *        extnValue         OCTET STRING }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector vec = new ASN1EncodableVector();
+        Enumeration             e = ordering.elements();
+
+        while (e.hasMoreElements())
+        {
+            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
+            Extension ext = (Extension)extensions.get(oid);
+            ASN1EncodableVector v = new ASN1EncodableVector();
+
+            v.add(oid);
+
+            if (ext.isCritical())
+            {
+                v.add(ASN1Boolean.getInstance(true));
+            }
+
+            v.add(ext.getExtnValue());
+
+            vec.add(new DERSequence(v));
+        }
+
+        return new DERSequence(vec);
+    }
+
+    public boolean equivalent(
+        Extensions other)
+    {
+        if (extensions.size() != other.extensions.size())
+        {
+            return false;
+        }
+
+        Enumeration     e1 = extensions.keys();
+
+        while (e1.hasMoreElements())
+        {
+            Object  key = e1.nextElement();
+
+            if (!extensions.get(key).equals(other.extensions.get(key)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public ASN1ObjectIdentifier[] getExtensionOIDs()
+    {
+        return toOidArray(ordering);
+    }
+    
+    public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
+    {
+        Vector oidVec = new Vector();
+
+        for (int i = 0; i != ordering.size(); i++)
+        {
+            Object oid = ordering.elementAt(i);
+
+            if (((Extension)extensions.get(oid)).isCritical() == isCritical)
+            {
+                oidVec.addElement(oid);
+            }
+        }
+
+        return toOidArray(oidVec);
+    }
+
+    private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)
+    {
+        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];
+
+        for (int i = 0; i != oids.length; i++)
+        {
+            oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);
+        }
+        return oids;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java b/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java
new file mode 100644
index 0000000..270ef1c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java
@@ -0,0 +1,94 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+
+/**
+ * Generator for X.509 extensions
+ */
+public class ExtensionsGenerator
+{
+    private Hashtable extensions = new Hashtable();
+    private Vector extOrdering = new Vector();
+
+    /**
+     * Reset the generator
+     */
+    public void reset()
+    {
+        extensions = new Hashtable();
+        extOrdering = new Vector();
+    }
+
+    /**
+     * Add an extension with the given oid and the passed in value to be included
+     * in the OCTET STRING associated with the extension.
+     *
+     * @param oid  OID for the extension.
+     * @param critical  true if critical, false otherwise.
+     * @param value the ASN.1 object to be included in the extension.
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean              critical,
+        ASN1Encodable        value)
+        throws IOException
+    {
+        this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+    }
+
+    /**
+     * Add an extension with the given oid and the passed in byte array to be wrapped in the
+     * OCTET STRING associated with the extension.
+     *
+     * @param oid OID for the extension.
+     * @param critical true if critical, false otherwise.
+     * @param value the byte array to be wrapped.
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions.containsKey(oid))
+        {
+            throw new IllegalArgumentException("extension " + oid + " already added");
+        }
+
+        extOrdering.addElement(oid);
+        extensions.put(oid, new Extension(oid, critical, new DEROctetString(value)));
+    }
+
+    /**
+     * Return true if there are no extension present in this generator.
+     *
+     * @return true if empty, false otherwise
+     */
+    public boolean isEmpty()
+    {
+        return extOrdering.isEmpty();
+    }
+
+    /**
+     * Generate an Extensions object based on the current state of the generator.
+     *
+     * @return  an X09Extensions object.
+     */
+    public Extensions generate()
+    {
+        Extension[] exts = new Extension[extOrdering.size()];
+
+        for (int i = 0; i != extOrdering.size(); i++)
+        {
+            exts[i] = (Extension)extensions.get(extOrdering.elementAt(i));
+        }
+
+        return new Extensions(exts);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java b/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
index 29fdd72..1829ecd 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
@@ -6,13 +6,12 @@
 import org.bouncycastle.asn1.ASN1Choice;
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x500.X500Name;
@@ -44,7 +43,7 @@
  * </pre>
  */
 public class GeneralName
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice
 {
     public static final int otherName                     = 0;
@@ -57,31 +56,25 @@
     public static final int iPAddress                     = 7;
     public static final int registeredID                  = 8;
 
-    DEREncodable      obj;
-    int               tag;
-   
-    public GeneralName(
-        X509Name  dirName)
-    {
-        this.obj = dirName;
-        this.tag = 4;
-    }
-
-    public GeneralName(
-        X500Name dirName)
-    {
-        this.obj = dirName;
-        this.tag = 4;
-    }
+    private ASN1Encodable obj;
+    private int           tag;
 
     /**
-     * @deprecated this constructor seems the wrong way round! Use GeneralName(tag, name).
+     * @deprecated use X500Name constructor.
+     * @param dirName
      */
-    public GeneralName(
-        DERObject name, int tag)
+        public GeneralName(
+        X509Name  dirName)
     {
-        this.obj = name;
-        this.tag = tag;
+        this.obj = X500Name.getInstance(dirName);
+        this.tag = 4;
+    }
+
+    public GeneralName(
+        X500Name  dirName)
+    {
+        this.obj = dirName;
+        this.tag = 4;
     }
 
     /**
@@ -154,11 +147,11 @@
         }
         else if (tag == registeredID)
         {
-            this.obj = new DERObjectIdentifier(name);
+            this.obj = new ASN1ObjectIdentifier(name);
         }
         else if (tag == directoryName)
         {
-            this.obj = new X509Name(name);
+            this.obj = new X500Name(name);
         }
         else if (tag == iPAddress)
         {
@@ -202,7 +195,7 @@
             case x400Address:
                 throw new IllegalArgumentException("unknown tag: " + tag);
             case directoryName:
-                return new GeneralName(tag, X509Name.getInstance(tagObj, true));
+                return new GeneralName(tag, X500Name.getInstance(tagObj, true));
             case ediPartyName:
                 return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));
             case uniformResourceIdentifier:
@@ -210,7 +203,7 @@
             case iPAddress:
                 return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false));
             case registeredID:
-                return new GeneralName(tag, DERObjectIdentifier.getInstance(tagObj, false));
+                return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false));
             }
         }
 
@@ -218,7 +211,7 @@
         {
             try
             {
-                return getInstance(ASN1Object.fromByteArray((byte[])obj));
+                return getInstance(ASN1Primitive.fromByteArray((byte[])obj));
             }
             catch (IOException e)
             {
@@ -241,7 +234,7 @@
         return tag;
     }
 
-    public DEREncodable getName()
+    public ASN1Encodable getName()
     {
         return obj;
     }
@@ -260,7 +253,7 @@
             buf.append(DERIA5String.getInstance(obj).getString());
             break;
         case directoryName:
-            buf.append(X509Name.getInstance(obj).toString());
+            buf.append(X500Name.getInstance(obj).toString());
             break;
         default:
             buf.append(obj.toString());
@@ -342,7 +335,7 @@
 
         for (int i = 0; i != maskVal; i++)
         {
-            addr[(i / 8) + offset] |= 1 << (i % 8);
+            addr[(i / 8) + offset] |= 1 << (7 - (i % 8));
         }
     }
 
@@ -364,7 +357,7 @@
 
         for (int i = 0; i != maskVal; i++)
         {
-            res[i / 16] |= 1 << (i % 16);
+            res[i / 16] |= 1 << (15 - (i % 16));
         }
         return res;
     }
@@ -432,7 +425,7 @@
         return val;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         if (tag == directoryName)       // directoryName is explicitly tagged as it is a CHOICE
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
index f35e10d..bd45407 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
@@ -1,30 +1,30 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class GeneralNames
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private final GeneralName[] names;
 
     public static GeneralNames getInstance(
         Object  obj)
     {
-        if (obj == null || obj instanceof GeneralNames)
+        if (obj instanceof GeneralNames)
         {
             return (GeneralNames)obj;
         }
 
-        if (obj instanceof ASN1Sequence)
+        if (obj != null)
         {
-            return new GeneralNames((ASN1Sequence)obj);
+            return new GeneralNames(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+        return null;
     }
 
     public static GeneralNames getInstance(
@@ -44,8 +44,15 @@
     {
         this.names = new GeneralName[] { name };
     }
-    
+
+
     public GeneralNames(
+        GeneralName[]  names)
+    {
+        this.names = names;
+    }
+
+    private GeneralNames(
         ASN1Sequence  seq)
     {
         this.names = new GeneralName[seq.size()];
@@ -71,7 +78,7 @@
      * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return new DERSequence(names);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java b/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
index 2a4b1f1..bf72ce6 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
@@ -2,12 +2,12 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
@@ -29,17 +29,17 @@
  * 
  */
 public class GeneralSubtree 
-    extends ASN1Encodable 
+    extends ASN1Object
 {
     private static final BigInteger ZERO = BigInteger.valueOf(0);
 
     private GeneralName base;
 
-    private DERInteger minimum;
+    private ASN1Integer minimum;
 
-    private DERInteger maximum;
+    private ASN1Integer maximum;
 
-    public GeneralSubtree(
+    private GeneralSubtree(
         ASN1Sequence seq) 
     {
         base = GeneralName.getInstance(seq.getObjectAt(0));
@@ -53,10 +53,10 @@
             switch (o.getTagNo()) 
             {
             case 0:
-                minimum = DERInteger.getInstance(o, false);
+                minimum = ASN1Integer.getInstance(o, false);
                 break;
             case 1:
-                maximum = DERInteger.getInstance(o, false);
+                maximum = ASN1Integer.getInstance(o, false);
                 break;
             default:
                 throw new IllegalArgumentException("Bad tag number: "
@@ -71,7 +71,7 @@
                 {
                     throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo());
                 }
-                minimum = DERInteger.getInstance(oMin, false);
+                minimum = ASN1Integer.getInstance(oMin, false);
             }
 
             {
@@ -80,7 +80,7 @@
                 {
                     throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo());
                 }
-                maximum = DERInteger.getInstance(oMax, false);
+                maximum = ASN1Integer.getInstance(oMax, false);
             }
 
             break;
@@ -116,7 +116,7 @@
         this.base = base;
         if (maximum != null)
         {
-            this.maximum = new DERInteger(maximum);
+            this.maximum = new ASN1Integer(maximum);
         }
         if (minimum == null)
         {
@@ -124,7 +124,7 @@
         }
         else
         {
-            this.minimum = new DERInteger(minimum);
+            this.minimum = new ASN1Integer(minimum);
         }
     }
 
@@ -195,9 +195,9 @@
      *       }
      * </pre>
      * 
-     * @return a DERObject
+     * @return a ASN1Primitive
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Holder.java b/src/main/java/org/bouncycastle/asn1/x509/Holder.java
index 2425847..6ae6e35 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/Holder.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/Holder.java
@@ -1,10 +1,10 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
@@ -38,15 +38,18 @@
  * </pre>
  */
 public class Holder
-    extends ASN1Encodable
+    extends ASN1Object
 {
+    public static final int V1_CERTIFICATE_HOLDER = 0;
+    public static final int V2_CERTIFICATE_HOLDER = 1;
+
     IssuerSerial baseCertificateID;
 
     GeneralNames entityName;
 
     ObjectDigestInfo objectDigestInfo;
 
-    private int version = 1;
+    private int version = V2_CERTIFICATE_HOLDER;
 
     public static Holder getInstance(Object obj)
     {
@@ -54,24 +57,24 @@
         {
             return (Holder)obj;
         }
-        else if (obj instanceof ASN1Sequence)
-        {
-            return new Holder((ASN1Sequence)obj);
-        }
         else if (obj instanceof ASN1TaggedObject)
         {
-            return new Holder((ASN1TaggedObject)obj);
+            return new Holder(ASN1TaggedObject.getInstance(obj));
+        }
+        else if (obj != null)
+        {
+            return new Holder(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     /**
-     * Constructor for a holder for an v1 attribute certificate.
+     * Constructor for a holder for an V1 attribute certificate.
      * 
      * @param tagObj The ASN.1 tagged holder object.
      */
-    public Holder(ASN1TaggedObject tagObj)
+    private Holder(ASN1TaggedObject tagObj)
     {
         switch (tagObj.getTagNo())
         {
@@ -88,11 +91,11 @@
     }
 
     /**
-     * Constructor for a holder for an v2 attribute certificate. *
+     * Constructor for a holder for an V2 attribute certificate.
      * 
      * @param seq The ASN.1 sequence.
      */
-    public Holder(ASN1Sequence seq)
+    private Holder(ASN1Sequence seq)
     {
         if (seq.size() > 3)
         {
@@ -125,11 +128,12 @@
 
     public Holder(IssuerSerial baseCertificateID)
     {
-        this.baseCertificateID = baseCertificateID;
+        this(baseCertificateID, V2_CERTIFICATE_HOLDER);
     }
 
     /**
-     * Constructs a holder from a IssuerSerial.
+     * Constructs a holder from a IssuerSerial for a V1 or V2 certificate.
+     * .
      * @param baseCertificateID The IssuerSerial.
      * @param version The version of the attribute certificate. 
      */
@@ -140,7 +144,7 @@
     }
     
     /**
-     * Returns 1 for v2 attribute certificates or 0 for v1 attribute
+     * Returns 1 for V2 attribute certificates or 0 for V1 attribute
      * certificates. 
      * @return The version of the attribute certificate.
      */
@@ -150,19 +154,18 @@
     }
 
     /**
-     * Constructs a holder with an entityName for v2 attribute certificates or
-     * with a subjectName for v1 attribute certificates.
+     * Constructs a holder with an entityName for V2 attribute certificates.
      * 
      * @param entityName The entity or subject name.
      */
     public Holder(GeneralNames entityName)
     {
-        this.entityName = entityName;
+        this(entityName, V2_CERTIFICATE_HOLDER);
     }
 
     /**
-     * Constructs a holder with an entityName for v2 attribute certificates or
-     * with a subjectName for v1 attribute certificates.
+     * Constructs a holder with an entityName for V2 attribute certificates or
+     * with a subjectName for V1 attribute certificates.
      * 
      * @param entityName The entity or subject name.
      * @param version The version of the attribute certificate. 
@@ -189,8 +192,8 @@
     }
 
     /**
-     * Returns the entityName for an v2 attribute certificate or the subjectName
-     * for an v1 attribute certificate.
+     * Returns the entityName for an V2 attribute certificate or the subjectName
+     * for an V1 attribute certificate.
      * 
      * @return The entityname or subjectname.
      */
@@ -204,7 +207,7 @@
         return objectDigestInfo;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         if (version == 1)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java b/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
index ceb639f..d082a9d 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
@@ -1,19 +1,19 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class IssuerSerial
-    extends ASN1Encodable
+    extends ASN1Object
 {
     GeneralNames            issuer;
-    DERInteger              serial;
+    ASN1Integer              serial;
     DERBitString            issuerUID;
 
     public static IssuerSerial getInstance(
@@ -48,7 +48,7 @@
         }
         
         issuer = GeneralNames.getInstance(seq.getObjectAt(0));
-        serial = DERInteger.getInstance(seq.getObjectAt(1));
+        serial = ASN1Integer.getInstance(seq.getObjectAt(1));
 
         if (seq.size() == 3)
         {
@@ -58,7 +58,7 @@
     
     public IssuerSerial(
         GeneralNames    issuer,
-        DERInteger      serial)
+        ASN1Integer      serial)
     {
         this.issuer = issuer;
         this.serial = serial;
@@ -69,7 +69,7 @@
         return issuer;
     }
 
-    public DERInteger getSerial()
+    public ASN1Integer getSerial()
     {
         return serial;
     }
@@ -89,7 +89,7 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
index 8900531..e31471c 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
@@ -1,11 +1,11 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBoolean;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
@@ -21,7 +21,7 @@
  * </pre>
  */
 public class IssuingDistributionPoint
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private DistributionPointName distributionPoint;
 
@@ -47,16 +47,16 @@
     public static IssuingDistributionPoint getInstance(
         Object obj)
     {
-        if (obj == null || obj instanceof IssuingDistributionPoint)
+        if (obj instanceof IssuingDistributionPoint)
         {
             return (IssuingDistributionPoint)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new IssuingDistributionPoint((ASN1Sequence)obj);
+            return new IssuingDistributionPoint(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     /**
@@ -127,9 +127,27 @@
     }
 
     /**
-     * Constructor from ASN1Sequence
+     * Shorthand Constructor from given details.
+     *
+     * @param distributionPoint
+     *            May contain an URI as pointer to most current CRL.
+     * @param indirectCRL
+     *            If <code>true</code> then the CRL contains revocation
+     *            information about certificates ssued by other CAs.
+     * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
      */
     public IssuingDistributionPoint(
+        DistributionPointName distributionPoint,
+        boolean indirectCRL,
+        boolean onlyContainsAttributeCerts)
+    {
+        this(distributionPoint, false, false, null, indirectCRL, onlyContainsAttributeCerts);
+    }
+
+    /**
+     * Constructor from ASN1Sequence
+     */
+    private IssuingDistributionPoint(
         ASN1Sequence seq)
     {
         this.seq = seq;
@@ -202,7 +220,7 @@
         return onlySomeReasons;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return seq;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java b/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
index 425e043..542a26b 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 /**
  * The KeyPurposeId object.
@@ -13,7 +13,7 @@
  * </pre>
  */
 public class KeyPurposeId
-    extends DERObjectIdentifier
+    extends ASN1ObjectIdentifier
 {
     private static final String id_kp = "1.3.6.1.5.5.7.3";
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java b/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
index 1383d39..02096f2 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
@@ -3,20 +3,34 @@
 import java.util.Enumeration;
 import java.util.Vector;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
 public class NameConstraints
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private ASN1Sequence permitted, excluded;
 
-    public NameConstraints(ASN1Sequence seq)
+    public static NameConstraints getInstance(Object obj)
+    {
+        if (obj instanceof NameConstraints)
+        {
+            return (NameConstraints)obj;
+        }
+        if (obj != null)
+        {
+            return new NameConstraints(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private NameConstraints(ASN1Sequence seq)
     {
         Enumeration e = seq.getObjects();
         while (e.hasMoreElements())
@@ -85,7 +99,7 @@
      * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
      * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
      */
-    public DERObject toASN1Object() 
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java b/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
index b881509..7a2d77e 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
@@ -1,13 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DEREnumerated;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
 /**
@@ -31,7 +32,7 @@
  * 
  */
 public class ObjectDigestInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
     /**
      * The public key is hashed.
@@ -48,9 +49,9 @@
      */
     public final static int otherObjectDigest = 2;
 
-    DEREnumerated digestedObjectType;
+    ASN1Enumerated digestedObjectType;
 
-    DERObjectIdentifier otherObjectTypeID;
+    ASN1ObjectIdentifier otherObjectTypeID;
 
     AlgorithmIdentifier digestAlgorithm;
 
@@ -59,18 +60,17 @@
     public static ObjectDigestInfo getInstance(
         Object obj)
     {
-        if (obj == null || obj instanceof ObjectDigestInfo)
+        if (obj instanceof ObjectDigestInfo)
         {
             return (ObjectDigestInfo)obj;
         }
 
-        if (obj instanceof ASN1Sequence)
+        if (obj != null)
         {
-            return new ObjectDigestInfo((ASN1Sequence)obj);
+            return new ObjectDigestInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("illegal object in getInstance: "
-            + obj.getClass().getName());
+        return null;
     }
 
     public static ObjectDigestInfo getInstance(
@@ -95,18 +95,17 @@
      */
     public ObjectDigestInfo(
         int digestedObjectType,
-        String otherObjectTypeID,
+        ASN1ObjectIdentifier otherObjectTypeID,
         AlgorithmIdentifier digestAlgorithm,
         byte[] objectDigest)
     {
-        this.digestedObjectType = new DEREnumerated(digestedObjectType);
+        this.digestedObjectType = new ASN1Enumerated(digestedObjectType);
         if (digestedObjectType == otherObjectDigest)
         {
-            this.otherObjectTypeID = new DERObjectIdentifier(otherObjectTypeID);
+            this.otherObjectTypeID = otherObjectTypeID;
         }
 
-        this.digestAlgorithm = digestAlgorithm; 
-
+        this.digestAlgorithm = digestAlgorithm;
         this.objectDigest = new DERBitString(objectDigest);
     }
 
@@ -125,7 +124,7 @@
 
         if (seq.size() == 4)
         {
-            otherObjectTypeID = DERObjectIdentifier.getInstance(seq.getObjectAt(1));
+            otherObjectTypeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));
             offset++;
         }
 
@@ -139,7 +138,7 @@
         return digestedObjectType;
     }
 
-    public DERObjectIdentifier getOtherObjectTypeID()
+    public ASN1ObjectIdentifier getOtherObjectTypeID()
     {
         return otherObjectTypeID;
     }
@@ -173,7 +172,7 @@
      *   
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java b/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
index b4373b0..d1de26f 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
@@ -1,19 +1,19 @@
 package org.bouncycastle.asn1.x509;
 
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
 public class PolicyInformation
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERObjectIdentifier   policyIdentifier;
+    private ASN1ObjectIdentifier   policyIdentifier;
     private ASN1Sequence          policyQualifiers;
 
-    public PolicyInformation(
+    private PolicyInformation(
         ASN1Sequence seq)
     {
         if (seq.size() < 1 || seq.size() > 2)
@@ -22,7 +22,7 @@
                     + seq.size());
         }
 
-        policyIdentifier = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+        policyIdentifier = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
 
         if (seq.size() > 1)
         {
@@ -31,13 +31,13 @@
     }
 
     public PolicyInformation(
-        DERObjectIdentifier policyIdentifier)
+        ASN1ObjectIdentifier policyIdentifier)
     {
         this.policyIdentifier = policyIdentifier;
     }
 
     public PolicyInformation(
-        DERObjectIdentifier policyIdentifier,
+        ASN1ObjectIdentifier policyIdentifier,
         ASN1Sequence        policyQualifiers)
     {
         this.policyIdentifier = policyIdentifier;
@@ -55,7 +55,7 @@
         return new PolicyInformation(ASN1Sequence.getInstance(obj));
     }
 
-    public DERObjectIdentifier getPolicyIdentifier()
+    public ASN1ObjectIdentifier getPolicyIdentifier()
     {
         return policyIdentifier;
     }
@@ -71,7 +71,7 @@
      *      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
      *              PolicyQualifierInfo OPTIONAL }
      */ 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
         
diff --git a/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
index 0047f6a..91c8725 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
@@ -3,16 +3,19 @@
 import java.math.BigInteger;
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
+/**
+ * @deprecated use org.bouncycastle.asn1.pkcs.RSAPublicKey
+ */
 public class RSAPublicKeyStructure
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private BigInteger  modulus;
     private BigInteger  publicExponent;
@@ -59,8 +62,8 @@
 
         Enumeration e = seq.getObjects();
 
-        modulus = DERInteger.getInstance(e.nextElement()).getPositiveValue();
-        publicExponent = DERInteger.getInstance(e.nextElement()).getPositiveValue();
+        modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+        publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
     }
 
     public BigInteger getModulus()
@@ -83,12 +86,12 @@
      * </pre>
      * <p>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(getModulus()));
-        v.add(new DERInteger(getPublicExponent()));
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
 
         return new DERSequence(v);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
index 8701b1e..29af48f 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
@@ -1,12 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 
 /**
  * The SubjectKeyIdentifier object.
@@ -15,7 +17,7 @@
  * </pre>
  */
 public class SubjectKeyIdentifier
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private byte[] keyidentifier;
 
@@ -33,47 +35,24 @@
         {
             return (SubjectKeyIdentifier)obj;
         }
-        
-        if (obj instanceof SubjectPublicKeyInfo) 
+        else if (obj != null)
         {
-            return new SubjectKeyIdentifier((SubjectPublicKeyInfo)obj);
-        }
-        
-        if (obj instanceof ASN1OctetString) 
-        {
-            return new SubjectKeyIdentifier((ASN1OctetString)obj);
+            return new SubjectKeyIdentifier(ASN1OctetString.getInstance(obj));
         }
 
-        if (obj instanceof X509Extension)
-        {
-            return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
-        }
-
-        throw new IllegalArgumentException("Invalid SubjectKeyIdentifier: " + obj.getClass().getName());
+        return null;
     }
-    
+
     public SubjectKeyIdentifier(
         byte[] keyid)
     {
-        this.keyidentifier=keyid;
+        this.keyidentifier = keyid;
     }
 
-    public SubjectKeyIdentifier(
-        ASN1OctetString  keyid)
+    protected SubjectKeyIdentifier(
+        ASN1OctetString keyid)
     {
-        this.keyidentifier=keyid.getOctets();
-    }
-
-    /**
-     * Calculates the keyidentifier using a SHA1 hash over the BIT STRING
-     * from SubjectPublicKeyInfo as defined in RFC3280.
-     *
-     * @param spki the subject public key info.
-     */
-    public SubjectKeyIdentifier(
-        SubjectPublicKeyInfo    spki)
-    {
-        this.keyidentifier = getDigest(spki);
+        this.keyidentifier = keyid.getOctets();
     }
 
     public byte[] getKeyIdentifier()
@@ -81,11 +60,25 @@
         return keyidentifier;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return new DEROctetString(keyidentifier);
     }
 
+
+    /**
+     * Calculates the keyidentifier using a SHA1 hash over the BIT STRING
+     * from SubjectPublicKeyInfo as defined in RFC3280.
+     *
+     * @param spki the subject public key info.
+     * @deprecated
+     */
+    public SubjectKeyIdentifier(
+        SubjectPublicKeyInfo    spki)
+    {
+        this.keyidentifier = getDigest(spki);
+    }
+
     /**
      * Return a RFC 3280 type 1 key identifier. As in:
      * <pre>
@@ -95,6 +88,7 @@
      * </pre>
      * @param keyInfo the key info object containing the subjectPublicKey field.
      * @return the key identifier.
+     * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createSubjectKeyIdentifier
      */
     public static SubjectKeyIdentifier createSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo)
     {
@@ -110,6 +104,7 @@
      * </pre>
      * @param keyInfo the key info object containing the subjectPublicKey field.
      * @return the key identifier.
+     * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createTruncatedSubjectKeyIdentifier
      */
     public static SubjectKeyIdentifier createTruncatedSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo)
     {
@@ -126,7 +121,9 @@
 
     private static byte[] getDigest(SubjectPublicKeyInfo spki)
     {
-        Digest digest = new SHA1Digest();
+        // BEGIN android-changed
+        Digest digest = new OpenSSLDigest.SHA1();
+        // END android-changed
         byte[]  resBuf = new byte[digest.getDigestSize()];
 
         byte[] bytes = spki.getPublicKeyData().getBytes();
diff --git a/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
index 9af439d..660ca05 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
@@ -6,11 +6,11 @@
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 /**
@@ -20,7 +20,7 @@
  * encoded one of these.
  */
 public class SubjectPublicKeyInfo
-    extends ASN1Encodable
+    extends ASN1Object
 {
     private AlgorithmIdentifier     algId;
     private DERBitString            keyData;
@@ -49,7 +49,7 @@
 
     public SubjectPublicKeyInfo(
         AlgorithmIdentifier algId,
-        DEREncodable        publicKey)
+        ASN1Encodable       publicKey)
     {
         this.keyData = new DERBitString(publicKey);
         this.algId = algId;
@@ -78,6 +78,15 @@
         this.keyData = DERBitString.getInstance(e.nextElement());
     }
 
+    public AlgorithmIdentifier getAlgorithm()
+    {
+        return algId;
+    }
+
+    /**
+     * @deprecated use getAlgorithm()
+     * @return    alg ID.
+     */
     public AlgorithmIdentifier getAlgorithmId()
     {
         return algId;
@@ -89,8 +98,9 @@
      *
      * @exception IOException - if the bit string doesn't represent a DER
      * encoded object.
+     * @return the public key as an ASN.1 primitive.
      */
-    public DERObject getPublicKey()
+    public ASN1Primitive parsePublicKey()
         throws IOException
     {
         ASN1InputStream         aIn = new ASN1InputStream(keyData.getBytes());
@@ -99,7 +109,26 @@
     }
 
     /**
-     * for when the public key is raw bits...
+     * for when the public key is an encoded object - if the bitstring
+     * can't be decoded this routine throws an IOException.
+     *
+     * @exception IOException - if the bit string doesn't represent a DER
+     * encoded object.
+     * @deprecated use parsePublicKey
+     * @return the public key as an ASN.1 primitive.
+     */
+    public ASN1Primitive getPublicKey()
+        throws IOException
+    {
+        ASN1InputStream         aIn = new ASN1InputStream(keyData.getBytes());
+
+        return aIn.readObject();
+    }
+
+    /**
+     * for when the public key is raw bits.
+     *
+     * @return the public key as the raw bit string...
      */
     public DERBitString getPublicKeyData()
     {
@@ -114,7 +143,7 @@
      *                          publicKey BIT STRING }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
index 128a1a1..ce657a7 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
@@ -2,14 +2,17 @@
 
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+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.DERGeneralizedTime;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.x500.X500Name;
 
 /**
  * PKIX RFC-2459 - TBSCertList object.
@@ -33,18 +36,16 @@
  * </pre>
  */
 public class TBSCertList
-    extends ASN1Encodable
+    extends ASN1Object
 {
     public static class CRLEntry
-        extends ASN1Encodable
+        extends ASN1Object
     {
         ASN1Sequence  seq;
 
-        DERInteger          userCertificate;
-        Time                revocationDate;
-        X509Extensions      crlEntryExtensions;
+        Extensions    crlEntryExtensions;
 
-        public CRLEntry(
+        private CRLEntry(
             ASN1Sequence  seq)
         {
             if (seq.size() < 2 || seq.size() > 3)
@@ -53,35 +54,51 @@
             }
             
             this.seq = seq;
-
-            userCertificate = DERInteger.getInstance(seq.getObjectAt(0));
-            revocationDate = Time.getInstance(seq.getObjectAt(1));
         }
 
-        public DERInteger getUserCertificate()
+        public static CRLEntry getInstance(Object o)
         {
-            return userCertificate;
+            if (o instanceof CRLEntry)
+            {
+                return ((CRLEntry)o);
+            }
+            else if (o != null)
+            {
+                return new CRLEntry(ASN1Sequence.getInstance(o));
+            }
+
+            return null;
+        }
+
+        public ASN1Integer getUserCertificate()
+        {
+            return ASN1Integer.getInstance(seq.getObjectAt(0));
         }
 
         public Time getRevocationDate()
         {
-            return revocationDate;
+            return Time.getInstance(seq.getObjectAt(1));
         }
 
-        public X509Extensions getExtensions()
+        public Extensions getExtensions()
         {
             if (crlEntryExtensions == null && seq.size() == 3)
             {
-                crlEntryExtensions = X509Extensions.getInstance(seq.getObjectAt(2));
+                crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2));
             }
             
             return crlEntryExtensions;
         }
 
-        public DERObject toASN1Object()
+        public ASN1Primitive toASN1Primitive()
         {
             return seq;
         }
+
+        public boolean hasExtensions()
+        {
+            return seq.size() == 3;
+        }
     }
 
     private class RevokedCertificatesEnumeration
@@ -101,7 +118,7 @@
 
         public Object nextElement()
         {
-            return new CRLEntry(ASN1Sequence.getInstance(en.nextElement()));
+            return CRLEntry.getInstance(en.nextElement());
         }
     }
 
@@ -119,15 +136,13 @@
         }
     }
 
-    ASN1Sequence     seq;
-
-    DERInteger              version;
+    ASN1Integer             version;
     AlgorithmIdentifier     signature;
-    X509Name                issuer;
+    X500Name                issuer;
     Time                    thisUpdate;
     Time                    nextUpdate;
     ASN1Sequence            revokedCertificates;
-    X509Extensions          crlExtensions;
+    Extensions              crlExtensions;
 
     public static TBSCertList getInstance(
         ASN1TaggedObject obj,
@@ -143,12 +158,12 @@
         {
             return (TBSCertList)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new TBSCertList((ASN1Sequence)obj);
+            return new TBSCertList(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public TBSCertList(
@@ -161,19 +176,17 @@
 
         int seqPos = 0;
 
-        this.seq = seq;
-
-        if (seq.getObjectAt(seqPos) instanceof DERInteger)
+        if (seq.getObjectAt(seqPos) instanceof ASN1Integer)
         {
-            version = DERInteger.getInstance(seq.getObjectAt(seqPos++));
+            version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++));
         }
         else
         {
-            version = new DERInteger(0);
+            version = null;  // version is optional
         }
 
         signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));
-        issuer = X509Name.getInstance(seq.getObjectAt(seqPos++));
+        issuer = X500Name.getInstance(seq.getObjectAt(seqPos++));
         thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
 
         if (seqPos < seq.size()
@@ -193,16 +206,20 @@
         if (seqPos < seq.size()
             && seq.getObjectAt(seqPos) instanceof DERTaggedObject)
         {
-            crlExtensions = X509Extensions.getInstance(seq.getObjectAt(seqPos));
+            crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true));
         }
     }
 
-    public int getVersion()
+    public int getVersionNumber()
     {
+        if (version == null)
+        {
+            return 1;
+        }
         return version.getValue().intValue() + 1;
     }
 
-    public DERInteger getVersionNumber()
+    public ASN1Integer getVersion()
     {
         return version;
     }
@@ -212,7 +229,7 @@
         return signature;
     }
 
-    public X509Name getIssuer()
+    public X500Name getIssuer()
     {
         return issuer;
     }
@@ -238,7 +255,7 @@
 
         for (int i = 0; i < entries.length; i++)
         {
-            entries[i] = new CRLEntry(ASN1Sequence.getInstance(revokedCertificates.getObjectAt(i)));
+            entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i));
         }
         
         return entries;
@@ -254,13 +271,39 @@
         return new RevokedCertificatesEnumeration(revokedCertificates.getObjects());
     }
 
-    public X509Extensions getExtensions()
+    public Extensions getExtensions()
     {
         return crlExtensions;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        return seq;
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (version != null)
+        {
+            v.add(version);
+        }
+        v.add(signature);
+        v.add(issuer);
+
+        v.add(thisUpdate);
+        if (nextUpdate != null)
+        {
+            v.add(nextUpdate);
+        }
+
+        // Add CRLEntries if they exist
+        if (revokedCertificates != null)
+        {
+            v.add(revokedCertificates);
+        }
+
+        if (crlExtensions != null)
+        {
+            v.add(new DERTaggedObject(0, crlExtensions));
+        }
+
+        return new DERSequence(v);
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java b/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
new file mode 100644
index 0000000..dc41964
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
@@ -0,0 +1,192 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERBitString;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * The TBSCertificate object.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      extensions        [ 3 ] Extensions OPTIONAL
+ *      }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ */
+public class TBSCertificate
+    extends ASN1Object
+{
+    ASN1Sequence            seq;
+
+    ASN1Integer             version;
+    ASN1Integer             serialNumber;
+    AlgorithmIdentifier     signature;
+    X500Name                issuer;
+    Time                    startDate, endDate;
+    X500Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+    DERBitString            issuerUniqueId;
+    DERBitString            subjectUniqueId;
+    Extensions              extensions;
+
+    public static TBSCertificate getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSCertificate getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSCertificate)
+        {
+            return (TBSCertificate)obj;
+        }
+        else if (obj != null)
+        {
+            return new TBSCertificate(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private TBSCertificate(
+        ASN1Sequence seq)
+    {
+        int         seqStart = 0;
+
+        this.seq = seq;
+
+        //
+        // some certficates don't include a version number - we assume v1
+        //
+        if (seq.getObjectAt(0) instanceof DERTaggedObject)
+        {
+            version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+        }
+        else
+        {
+            seqStart = -1;          // field 0 is missing!
+            version = new ASN1Integer(0);
+        }
+
+        serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));
+
+        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
+        issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));
+
+        //
+        // before and after dates
+        //
+        ASN1Sequence  dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);
+
+        startDate = Time.getInstance(dates.getObjectAt(0));
+        endDate = Time.getInstance(dates.getObjectAt(1));
+
+        subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));
+
+        //
+        // public key info.
+        //
+        subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));
+
+        for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)
+        {
+            DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+            switch (extra.getTagNo())
+            {
+            case 1:
+                issuerUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 2:
+                subjectUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 3:
+                extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true));
+            }
+        }
+    }
+
+    public int getVersionNumber()
+    {
+        return version.getValue().intValue() + 1;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public X500Name getIssuer()
+    {
+        return issuer;
+    }
+
+    public Time getStartDate()
+    {
+        return startDate;
+    }
+
+    public Time getEndDate()
+    {
+        return endDate;
+    }
+
+    public X500Name getSubject()
+    {
+        return subject;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return subjectPublicKeyInfo;
+    }
+
+    public DERBitString getIssuerUniqueId()
+    {
+        return issuerUniqueId;
+    }
+
+    public DERBitString getSubjectUniqueId()
+    {
+        return subjectUniqueId;
+    }
+
+    public Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
index 36425d7..2c5d920 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
@@ -1,13 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+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.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
 
 /**
  * The TBSCertificate object.
@@ -30,17 +31,17 @@
  * will parse them, but you really shouldn't be creating new ones.
  */
 public class TBSCertificateStructure
-    extends ASN1Encodable
+    extends ASN1Object
     implements X509ObjectIdentifiers, PKCSObjectIdentifiers
 {
     ASN1Sequence            seq;
 
-    DERInteger              version;
-    DERInteger              serialNumber;
+    ASN1Integer             version;
+    ASN1Integer             serialNumber;
     AlgorithmIdentifier     signature;
-    X509Name                issuer;
+    X500Name                issuer;
     Time                    startDate, endDate;
-    X509Name                subject;
+    X500Name                subject;
     SubjectPublicKeyInfo    subjectPublicKeyInfo;
     DERBitString            issuerUniqueId;
     DERBitString            subjectUniqueId;
@@ -80,18 +81,18 @@
         //
         if (seq.getObjectAt(0) instanceof DERTaggedObject)
         {
-            version = DERInteger.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+            version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
         }
         else
         {
             seqStart = -1;          // field 0 is missing!
-            version = new DERInteger(0);
+            version = new ASN1Integer(0);
         }
 
-        serialNumber = DERInteger.getInstance(seq.getObjectAt(seqStart + 1));
+        serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));
 
         signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
-        issuer = X509Name.getInstance(seq.getObjectAt(seqStart + 3));
+        issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));
 
         //
         // before and after dates
@@ -101,7 +102,7 @@
         startDate = Time.getInstance(dates.getObjectAt(0));
         endDate = Time.getInstance(dates.getObjectAt(1));
 
-        subject = X509Name.getInstance(seq.getObjectAt(seqStart + 5));
+        subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));
 
         //
         // public key info.
@@ -131,12 +132,12 @@
         return version.getValue().intValue() + 1;
     }
 
-    public DERInteger getVersionNumber()
+    public ASN1Integer getVersionNumber()
     {
         return version;
     }
 
-    public DERInteger getSerialNumber()
+    public ASN1Integer getSerialNumber()
     {
         return serialNumber;
     }
@@ -146,7 +147,7 @@
         return signature;
     }
 
-    public X509Name getIssuer()
+    public X500Name getIssuer()
     {
         return issuer;
     }
@@ -161,7 +162,7 @@
         return endDate;
     }
 
-    public X509Name getSubject()
+    public X500Name getSubject()
     {
         return subject;
     }
@@ -186,7 +187,7 @@
         return extensions;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return seq;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Time.java b/src/main/java/org/bouncycastle/asn1/x509/Time.java
index d51209d..5bffedc 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/Time.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/Time.java
@@ -1,22 +1,22 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Choice;
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERGeneralizedTime;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERUTCTime;
-
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.SimpleTimeZone;
 
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERUTCTime;
+
 public class Time
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice
 {
-    DERObject   time;
+    ASN1Primitive time;
 
     public static Time getInstance(
         ASN1TaggedObject obj,
@@ -26,7 +26,7 @@
     }
 
     public Time(
-        DERObject   time)
+        ASN1Primitive   time)
     {
         if (!(time instanceof DERUTCTime)
             && !(time instanceof DERGeneralizedTime))
@@ -121,7 +121,7 @@
      *             generalTime    GeneralizedTime }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return time;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
index 1c3016d..437d6c0 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
@@ -1,7 +1,7 @@
 package org.bouncycastle.asn1.x509;
 
 import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.DERUTCTime;
@@ -24,13 +24,13 @@
  */
 public class V1TBSCertificateGenerator
 {
-    DERTaggedObject         version = new DERTaggedObject(0, new DERInteger(0));
+    DERTaggedObject         version = new DERTaggedObject(true, 0, new ASN1Integer(0));
 
-    DERInteger              serialNumber;
+    ASN1Integer              serialNumber;
     AlgorithmIdentifier     signature;
-    X509Name                issuer;
+    X500Name                issuer;
     Time                    startDate, endDate;
-    X509Name                subject;
+    X500Name                subject;
     SubjectPublicKeyInfo    subjectPublicKeyInfo;
 
     public V1TBSCertificateGenerator()
@@ -38,7 +38,7 @@
     }
 
     public void setSerialNumber(
-        DERInteger  serialNumber)
+        ASN1Integer  serialNumber)
     {
         this.serialNumber = serialNumber;
     }
@@ -49,16 +49,19 @@
         this.signature = signature;
     }
 
+        /**
+     * @deprecated use X500Name method
+     */
     public void setIssuer(
         X509Name    issuer)
     {
-        this.issuer = issuer;
+        this.issuer = X500Name.getInstance(issuer.toASN1Primitive());
     }
 
     public void setIssuer(
         X500Name issuer)
     {
-        this.issuer = X509Name.getInstance(issuer.getDERObject());
+        this.issuer = issuer;
     }
 
     public void setStartDate(
@@ -85,16 +88,19 @@
         this.endDate = new Time(endDate);
     }
 
+        /**
+     * @deprecated use X500Name method
+     */
     public void setSubject(
         X509Name    subject)
     {
-        this.subject = subject;
+        this.subject = X500Name.getInstance(subject.toASN1Primitive());
     }
 
     public void setSubject(
         X500Name subject)
     {
-        this.subject = X509Name.getInstance(subject.getDERObject());
+        this.subject = subject;
     }
 
     public void setSubjectPublicKeyInfo(
@@ -103,7 +109,7 @@
         this.subjectPublicKeyInfo = pubKeyInfo;
     }
 
-    public TBSCertificateStructure generateTBSCertificate()
+    public TBSCertificate generateTBSCertificate()
     {
         if ((serialNumber == null) || (signature == null)
             || (issuer == null) || (startDate == null) || (endDate == null)
@@ -133,6 +139,6 @@
 
         seq.add(subjectPublicKeyInfo);
 
-        return new TBSCertificateStructure(new DERSequence(seq));
+        return TBSCertificate.getInstance(new DERSequence(seq));
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/V2Form.java b/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
index 1eb77d1..ed5c6ab 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
@@ -1,15 +1,15 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
 public class V2Form
-    extends ASN1Encodable
+    extends ASN1Object
 {
     GeneralNames        issuerName;
     IssuerSerial        baseCertificateID;
@@ -106,7 +106,7 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
index 6fccbd0..3d923b6 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
@@ -1,8 +1,8 @@
 package org.bouncycastle.asn1.x509;
 
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.DERUTCTime;
@@ -28,15 +28,15 @@
  */
 public class V3TBSCertificateGenerator
 {
-    DERTaggedObject         version = new DERTaggedObject(0, new DERInteger(2));
+    DERTaggedObject         version = new DERTaggedObject(true, 0, new ASN1Integer(2));
 
-    DERInteger              serialNumber;
+    ASN1Integer              serialNumber;
     AlgorithmIdentifier     signature;
-    X509Name                issuer;
+    X500Name                issuer;
     Time                    startDate, endDate;
-    X509Name                subject;
+    X500Name                subject;
     SubjectPublicKeyInfo    subjectPublicKeyInfo;
-    X509Extensions          extensions;
+    Extensions              extensions;
 
     private boolean altNamePresentAndCritical;
     private DERBitString issuerUniqueID;
@@ -47,7 +47,7 @@
     }
 
     public void setSerialNumber(
-        DERInteger  serialNumber)
+        ASN1Integer  serialNumber)
     {
         this.serialNumber = serialNumber;
     }
@@ -58,16 +58,19 @@
         this.signature = signature;
     }
 
+        /**
+     * @deprecated use X500Name method
+     */
     public void setIssuer(
         X509Name    issuer)
     {
-        this.issuer = issuer;
+        this.issuer = X500Name.getInstance(issuer);
     }
 
     public void setIssuer(
         X500Name issuer)
     {
-        this.issuer = X509Name.getInstance(issuer.getDERObject());
+        this.issuer = issuer;
     }
     
     public void setStartDate(
@@ -94,16 +97,19 @@
         this.endDate = endDate;
     }
 
+        /**
+     * @deprecated use X500Name method
+     */
     public void setSubject(
         X509Name    subject)
     {
-        this.subject = subject;
+        this.subject = X500Name.getInstance(subject.toASN1Primitive());
     }
 
     public void setSubject(
         X500Name subject)
     {
-        this.subject = X509Name.getInstance(subject.getDERObject());
+        this.subject = subject;
     }
 
     public void setIssuerUniqueID(
@@ -124,13 +130,23 @@
         this.subjectPublicKeyInfo = pubKeyInfo;
     }
 
+    /**
+     * @deprecated use method taking Extensions
+     * @param extensions
+     */
     public void setExtensions(
         X509Extensions    extensions)
     {
+        setExtensions(Extensions.getInstance(extensions));
+    }
+
+    public void setExtensions(
+        Extensions    extensions)
+    {
         this.extensions = extensions;
         if (extensions != null)
         {
-            X509Extension altName = extensions.getExtension(X509Extensions.SubjectAlternativeName);
+            Extension altName = extensions.getExtension(Extension.subjectAlternativeName);
 
             if (altName != null && altName.isCritical())
             {
@@ -139,7 +155,7 @@
         }
     }
 
-    public TBSCertificateStructure generateTBSCertificate()
+    public TBSCertificate generateTBSCertificate()
     {
         if ((serialNumber == null) || (signature == null)
             || (issuer == null) || (startDate == null) || (endDate == null)
@@ -188,9 +204,9 @@
 
         if (extensions != null)
         {
-            v.add(new DERTaggedObject(3, extensions));
+            v.add(new DERTaggedObject(true, 3, extensions));
         }
 
-        return new TBSCertificateStructure(new DERSequence(v));
+        return TBSCertificate.getInstance(new DERSequence(v));
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
index 8559b69..6830030 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
@@ -1,12 +1,13 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+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.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
 
 /**
  * an X509Certificate structure.
@@ -17,9 +18,10 @@
  *      signature               BIT STRING
  *  }
  * </pre>
+ * @deprecated use org.bouncycastle.asn1.x509.Certificate
  */
 public class X509CertificateStructure
-    extends ASN1Encodable
+    extends ASN1Object
     implements X509ObjectIdentifiers, PKCSObjectIdentifiers
 {
     ASN1Sequence  seq;
@@ -80,12 +82,12 @@
         return tbsCert.getVersion();
     }
 
-    public DERInteger getSerialNumber()
+    public ASN1Integer getSerialNumber()
     {
         return tbsCert.getSerialNumber();
     }
 
-    public X509Name getIssuer()
+    public X500Name getIssuer()
     {
         return tbsCert.getIssuer();
     }
@@ -100,7 +102,7 @@
         return tbsCert.getEndDate();
     }
 
-    public X509Name getSubject()
+    public X500Name getSubject()
     {
         return tbsCert.getSubject();
     }
@@ -120,7 +122,7 @@
         return sig;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return seq;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java b/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
index 6098c27..0ae0f80 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
@@ -1,14 +1,14 @@
 package org.bouncycastle.asn1.x509;
 
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DERGeneralizedTime;
 import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERPrintableString;
 import org.bouncycastle.asn1.DERUTF8String;
 
-import java.io.IOException;
-
 /**
  * The default converter for X509 DN entries when going from their
  * string value to ASN.1 strings.
@@ -24,8 +24,8 @@
      * @param value the value associated with it
      * @return the ASN.1 equivalent for the string value.
      */
-    public DERObject getConvertedValue(
-        DERObjectIdentifier  oid,
+    public ASN1Primitive getConvertedValue(
+        ASN1ObjectIdentifier  oid,
         String               value)
     {
         if (value.length() != 0 && value.charAt(0) == '#')
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
index 8c2cab4..f020bcb 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
@@ -3,9 +3,9 @@
 import java.io.IOException;
 
 import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DERBoolean;
 
 /**
@@ -169,7 +169,7 @@
     public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55");
         
     boolean             critical;
-    ASN1OctetString      value;
+    ASN1OctetString     value;
 
     public X509Extension(
         DERBoolean              critical,
@@ -209,7 +209,6 @@
             return this.getValue().hashCode();
         }
 
-        
         return ~this.getValue().hashCode();
     }
 
@@ -233,13 +232,13 @@
      * @return the object the value string contains
      * @exception IllegalArgumentException if conversion is not possible
      */
-    public static ASN1Object convertValueToObject(
+    public static ASN1Primitive convertValueToObject(
         X509Extension ext)
         throws IllegalArgumentException
     {
         try
         {
-            return ASN1Object.fromByteArray(ext.getValue().getOctets());
+            return ASN1Primitive.fromByteArray(ext.getValue().getOctets());
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
index a9819f4..5e9bb46 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
@@ -4,19 +4,22 @@
 import java.util.Hashtable;
 import java.util.Vector;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBoolean;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
+/**
+ * @deprecated use Extensions
+ */
 public class X509Extensions
-    extends ASN1Encodable
+    extends ASN1Object
 {
     /**
      * Subject Directory Attributes
@@ -227,6 +230,11 @@
             return new X509Extensions((ASN1Sequence)obj);
         }
 
+        if (obj instanceof Extensions)
+        {
+            return new X509Extensions((ASN1Sequence)((Extensions)obj).toASN1Primitive());
+        }
+
         if (obj instanceof ASN1TaggedObject)
         {
             return getInstance(((ASN1TaggedObject)obj).getObject());
@@ -299,14 +307,14 @@
 
         while (e.hasMoreElements())
         {
-            this.ordering.addElement(new ASN1ObjectIdentifier(((DERObjectIdentifier)e.nextElement()).getId())); 
+            this.ordering.addElement(ASN1ObjectIdentifier.getInstance(e.nextElement()));
         }
 
         e = this.ordering.elements();
 
         while (e.hasMoreElements())
         {
-            ASN1ObjectIdentifier     oid = new ASN1ObjectIdentifier(((DERObjectIdentifier)e.nextElement()).getId());
+            ASN1ObjectIdentifier     oid = ASN1ObjectIdentifier.getInstance(e.nextElement());
             X509Extension           ext = (X509Extension)extensions.get(oid);
 
             this.extensions.put(oid, ext);
@@ -359,7 +367,7 @@
      * @return the extension if it's present, null otherwise.
      */
     public X509Extension getExtension(
-        ASN1ObjectIdentifier oid)
+        DERObjectIdentifier oid)
     {
         return (X509Extension)extensions.get(oid);
     }
@@ -370,7 +378,7 @@
      * @return
      */
     public X509Extension getExtension(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         return (X509Extension)extensions.get(oid);
     }
@@ -385,14 +393,14 @@
      *        extnValue         OCTET STRING }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector     vec = new ASN1EncodableVector();
         Enumeration             e = ordering.elements();
 
         while (e.hasMoreElements())
         {
-            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
+            ASN1ObjectIdentifier    oid = (ASN1ObjectIdentifier)e.nextElement();
             X509Extension           ext = (X509Extension)extensions.get(oid);
             ASN1EncodableVector     v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
index 0487c8e..468d1b9 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
@@ -1,16 +1,18 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROctetString;
-
 import java.io.IOException;
 import java.util.Hashtable;
 import java.util.Vector;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+
 /**
  * Generator for X.509 extensions
+ * @deprecated use org.bouncycastle.asn1.x509.ExtensionsGenerator
  */
 public class X509ExtensionsGenerator
 {
@@ -27,6 +29,28 @@
     }
 
     /**
+     * @deprecated use ASN1ObjectIdentifier
+     */
+    public void addExtension(
+        DERObjectIdentifier oid,
+        boolean             critical,
+        ASN1Encodable       value)
+    {
+        addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+    }
+
+    /**
+     * @deprecated use ASN1ObjectIdentifier
+     */
+    public void addExtension(
+        DERObjectIdentifier oid,
+        boolean             critical,
+        byte[]              value)
+    {
+        addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+    }
+
+    /**
      * Add an extension with the given oid and the passed in value to be included
      * in the OCTET STRING associated with the extension.
      *
@@ -35,13 +59,13 @@
      * @param value the ASN.1 object to be included in the extension.
      */
     public void addExtension(
-        DERObjectIdentifier oid,
+        ASN1ObjectIdentifier oid,
         boolean             critical,
-        DEREncodable        value)
+        ASN1Encodable       value)
     {
         try
         {
-            this.addExtension(oid, critical, value.getDERObject().getEncoded(ASN1Encodable.DER));
+            this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
         }
         catch (IOException e)
         {
@@ -58,7 +82,7 @@
      * @param value the byte array to be wrapped.
      */
     public void addExtension(
-        DERObjectIdentifier oid,
+        ASN1ObjectIdentifier oid,
         boolean             critical,
         byte[]              value)
     {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
index 89638dd..2dc630f 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
@@ -7,16 +7,16 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1String;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
-import org.bouncycastle.asn1.DERString;
 import org.bouncycastle.asn1.DERUniversalString;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.x500.X500Name;
@@ -36,177 +36,183 @@
  * @deprecated use org.bouncycastle.asn1.x500.X500Name.
  */
 public class X509Name
-    extends ASN1Encodable
+    extends ASN1Object
 {
     /**
      * country code - StringType(SIZE(2))
+     * @deprecated use a X500NameStyle
      */
-    public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
+    public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6");
 
     /**
      * organization - StringType(SIZE(1..64))
+     * @deprecated use a X500NameStyle
      */
-    public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
+    public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10");
 
     /**
      * organizational unit name - StringType(SIZE(1..64))
+     * @deprecated use a X500NameStyle
      */
-    public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
+    public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11");
 
     /**
      * Title
+     * @deprecated use a X500NameStyle
      */
-    public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
+    public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12");
 
     /**
      * common name - StringType(SIZE(1..64))
+     * @deprecated use a X500NameStyle
      */
-    public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
+    public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3");
 
     /**
      * device serial number name - StringType(SIZE(1..64))
      */
-    public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
+    public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5");
 
     /**
      * street - StringType(SIZE(1..64))
      */
-    public static final DERObjectIdentifier STREET = new DERObjectIdentifier("2.5.4.9");
+    public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9");
     
     /**
      * device serial number name - StringType(SIZE(1..64))
      */
-    public static final DERObjectIdentifier SERIALNUMBER = SN;
+    public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
 
     /**
      * locality name - StringType(SIZE(1..64))
      */
-    public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
+    public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7");
 
     /**
      * state, or province name - StringType(SIZE(1..64))
      */
-    public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
+    public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8");
 
     /**
      * Naming attributes of type X520name
      */
-    public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4");
-    public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42");
-    public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43");
-    public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44");
-    public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45");
+    public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4");
+    public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42");
+    public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43");
+    public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44");
+    public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45");
 
     /**
      * businessCategory - DirectoryString(SIZE(1..128)
      */
-    public static final DERObjectIdentifier BUSINESS_CATEGORY = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(
                     "2.5.4.15");
 
     /**
      * postalCode - DirectoryString(SIZE(1..40)
      */
-    public static final DERObjectIdentifier POSTAL_CODE = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(
                     "2.5.4.17");
     
     /**
      * dnQualifier - DirectoryString(SIZE(1..64)
      */
-    public static final DERObjectIdentifier DN_QUALIFIER = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(
                     "2.5.4.46");
 
     /**
      * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
      */
-    public static final DERObjectIdentifier PSEUDONYM = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(
                     "2.5.4.65");
 
 
     /**
      * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
      */
-    public static final DERObjectIdentifier DATE_OF_BIRTH = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(
                     "1.3.6.1.5.5.7.9.1");
 
     /**
      * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
      */
-    public static final DERObjectIdentifier PLACE_OF_BIRTH = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier(
                     "1.3.6.1.5.5.7.9.2");
 
     /**
      * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
      */
-    public static final DERObjectIdentifier GENDER = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier(
                     "1.3.6.1.5.5.7.9.3");
 
     /**
      * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
      * codes only
      */
-    public static final DERObjectIdentifier COUNTRY_OF_CITIZENSHIP = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier(
                     "1.3.6.1.5.5.7.9.4");
 
     /**
      * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
      * codes only
      */
-    public static final DERObjectIdentifier COUNTRY_OF_RESIDENCE = new DERObjectIdentifier(
+    public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier(
                     "1.3.6.1.5.5.7.9.5");
 
 
     /**
      * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
      */
-    public static final DERObjectIdentifier NAME_AT_BIRTH =  new DERObjectIdentifier("1.3.36.8.3.14");
+    public static final ASN1ObjectIdentifier NAME_AT_BIRTH =  new ASN1ObjectIdentifier("1.3.36.8.3.14");
 
     /**
      * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
      * DirectoryString(SIZE(1..30))
      */
-    public static final DERObjectIdentifier POSTAL_ADDRESS = new DERObjectIdentifier("2.5.4.16");
+    public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16");
 
     /**
      * RFC 2256 dmdName
      */
-    public static final DERObjectIdentifier DMD_NAME = new DERObjectIdentifier("2.5.4.54");
+    public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54");
 
     /**
      * id-at-telephoneNumber
      */
-    public static final DERObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
+    public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
 
     /**
      * id-at-name
      */
-    public static final DERObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
+    public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
 
     /**
      * Email address (RSA PKCS#9 extension) - IA5String.
      * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+     * @deprecated use a X500NameStyle
      */
-    public static final DERObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+    public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
     
     /**
      * more from PKCS#9
      */
-    public static final DERObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
-    public static final DERObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+    public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+    public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
     
     /**
      * email address in Verisign certificates
      */
-    public static final DERObjectIdentifier E = EmailAddress;
+    public static final ASN1ObjectIdentifier E = EmailAddress;
     
     /*
      * others...
      */
-    public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25");
+    public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
 
     /**
      * LDAP User id.
      */
-    public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1");
+    public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
 
     /**
      * determines whether or not strings should be processed and printed
@@ -376,7 +382,7 @@
         }
         else if (obj instanceof X500Name)
         {
-            return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).getDERObject()));
+            return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).toASN1Primitive()));
         }
         else if (obj != null)
         {
@@ -404,23 +410,23 @@
 
         while (e.hasMoreElements())
         {
-            ASN1Set         set = ASN1Set.getInstance(((DEREncodable)e.nextElement()).getDERObject());
+            ASN1Set         set = ASN1Set.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());
 
             for (int i = 0; i < set.size(); i++) 
             {
-                   ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i));
+                   ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i).toASN1Primitive());
 
                    if (s.size() != 2)
                    {
                        throw new IllegalArgumentException("badly sized pair");
                    }
 
-                   ordering.addElement(DERObjectIdentifier.getInstance(s.getObjectAt(0)));
+                   ordering.addElement(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)));
                    
-                   DEREncodable value = s.getObjectAt(1);
-                   if (value instanceof DERString && !(value instanceof DERUniversalString))
+                   ASN1Encodable value = s.getObjectAt(1);
+                   if (value instanceof ASN1String && !(value instanceof DERUniversalString))
                    {
-                       String v = ((DERString)value).getString();
+                       String v = ((ASN1String)value).getString();
                        if (v.length() > 0 && v.charAt(0) == '#')
                        {
                            values.addElement("\\" + v);
@@ -432,7 +438,14 @@
                    }
                    else
                    {
-                       values.addElement("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
+                       try
+                       {
+                           values.addElement("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+                       }
+                       catch (IOException e1)
+                       {
+                           throw new IllegalArgumentException("cannot encode value");
+                       }
                    }
                    // BEGIN android-changed
                    added.addElement(Boolean.valueOf(i != 0));
@@ -513,7 +526,7 @@
 
         for (int i = 0; i != this.ordering.size(); i++)
         {
-            DERObjectIdentifier     oid = (DERObjectIdentifier)this.ordering.elementAt(i);
+            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)this.ordering.elementAt(i);
 
             if (attributes.get(oid) == null)
             {
@@ -625,7 +638,7 @@
      * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
      * some such, converting it into an ordered set of name attributes. lookUp
      * should provide a table of lookups, indexed by lowercase only strings and
-     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
+     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
      * will be processed automatically.
      * <br>
      * If reverse is true, create the encoded version of the sequence
@@ -642,20 +655,20 @@
         this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
     }
 
-    private DERObjectIdentifier decodeOID(
+    private ASN1ObjectIdentifier decodeOID(
         String      name,
         Hashtable   lookUp)
     {
         if (Strings.toUpperCase(name).startsWith("OID."))
         {
-            return new DERObjectIdentifier(name.substring(4));
+            return new ASN1ObjectIdentifier(name.substring(4));
         }
         else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
         {
-            return new DERObjectIdentifier(name);
+            return new ASN1ObjectIdentifier(name);
         }
 
-        DERObjectIdentifier oid = (DERObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
         if (oid == null)
         {
             throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
@@ -668,7 +681,7 @@
      * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
      * some such, converting it into an ordered set of name attributes. lookUp
      * should provide a table of lookups, indexed by lowercase only strings and
-     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
+     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
      * will be processed automatically. The passed in converter is used to convert the
      * string values to the right of each equals sign to their ASN.1 counterparts.
      * <br>
@@ -700,7 +713,7 @@
 
             String              name = token.substring(0, index);
             String              value = token.substring(index + 1);
-            DERObjectIdentifier oid = decodeOID(name, lookUp);
+            ASN1ObjectIdentifier oid = decodeOID(name, lookUp);
 
             if (value.indexOf('+') > 0)
             {
@@ -799,7 +812,7 @@
      * were found, with the DN label corresponding to passed in oid.
      */
     public Vector getValues(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         Vector  v = new Vector();
 
@@ -823,18 +836,18 @@
         return v;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         if (seq == null)
         {
             ASN1EncodableVector  vec = new ASN1EncodableVector();
             ASN1EncodableVector  sVec = new ASN1EncodableVector();
-            DERObjectIdentifier  lstOid = null;
+            ASN1ObjectIdentifier  lstOid = null;
             
             for (int i = 0; i != ordering.size(); i++)
             {
                 ASN1EncodableVector     v = new ASN1EncodableVector();
-                DERObjectIdentifier     oid = (DERObjectIdentifier)ordering.elementAt(i);
+                ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
 
                 v.add(oid);
 
@@ -887,9 +900,9 @@
             return false;
         }
 
-        DERObject derO = ((DEREncodable)obj).getDERObject();
+        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
 
-        if (this.getDERObject().equals(derO))
+        if (this.toASN1Primitive().equals(derO))
         {
             return true;
         }
@@ -914,8 +927,8 @@
 
         for (int i = 0; i < orderingSize; i++)
         {
-            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
-            DERObjectIdentifier  oOid = (DERObjectIdentifier)other.ordering.elementAt(i);
+            ASN1ObjectIdentifier  oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+            ASN1ObjectIdentifier  oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(i);
 
             if (oid.equals(oOid))
             {
@@ -975,9 +988,9 @@
             return false;
         }
         
-        DERObject derO = ((DEREncodable)obj).getDERObject();
+        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
         
-        if (this.getDERObject().equals(derO))
+        if (this.toASN1Primitive().equals(derO))
         {
             return true;
         }
@@ -1019,7 +1032,7 @@
         for (int i = start; i != end; i += delta)
         {
             boolean              found = false;
-            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
+            ASN1ObjectIdentifier  oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
             String               value = (String)values.elementAt(i);
 
             for (int j = 0; j < orderingSize; j++)
@@ -1029,7 +1042,7 @@
                     continue;
                 }
 
-                DERObjectIdentifier oOid = (DERObjectIdentifier)other.ordering.elementAt(j);
+                ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(j);
 
                 if (oid.equals(oOid))
                 {
@@ -1078,22 +1091,22 @@
         
         if (value.length() > 0 && value.charAt(0) == '#')
         {
-            DERObject obj = decodeObject(value);
+            ASN1Primitive obj = decodeObject(value);
 
-            if (obj instanceof DERString)
+            if (obj instanceof ASN1String)
             {
-                value = Strings.toLowerCase(((DERString)obj).getString().trim());
+                value = Strings.toLowerCase(((ASN1String)obj).getString().trim());
             }
         }
 
         return value;
     }
 
-    private ASN1Object decodeObject(String oValue)
+    private ASN1Primitive decodeObject(String oValue)
     {
         try
         {
-            return ASN1Object.fromByteArray(Hex.decode(oValue.substring(1)));
+            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
         }
         catch (IOException e)
         {
@@ -1129,7 +1142,7 @@
     private void appendValue(
         StringBuffer        buf,
         Hashtable           oidSymbols,
-        DERObjectIdentifier oid,
+        ASN1ObjectIdentifier oid,
         String              value)
     {
         String  sym = (String)oidSymbols.get(oid);
@@ -1204,14 +1217,14 @@
             {
                 ava.append('+');
                 appendValue(ava, oidSymbols,
-                    (DERObjectIdentifier)ordering.elementAt(i),
+                    (ASN1ObjectIdentifier)ordering.elementAt(i),
                     (String)values.elementAt(i));
             }
             else
             {
                 ava = new StringBuffer();
                 appendValue(ava, oidSymbols,
-                    (DERObjectIdentifier)ordering.elementAt(i),
+                    (ASN1ObjectIdentifier)ordering.elementAt(i),
                     (String)values.elementAt(i));
                 components.addElement(ava);
             }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
index 5011322..5d919e1 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
@@ -1,13 +1,13 @@
 package org.bouncycastle.asn1.x509;
 
+import java.io.IOException;
+
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DERPrintableString;
 import org.bouncycastle.util.Strings;
 
-import java.io.IOException;
-
 /**
  * It turns out that the number of standard ways the fields in a DN should be 
  * encoded into their ASN.1 counterparts is rapidly approaching the
@@ -19,8 +19,8 @@
  * public class X509DirEntryConverter
  *     extends X509NameEntryConverter
  * {
- *     public DERObject getConvertedValue(
- *         DERObjectIdentifier  oid,
+ *     public ASN1Primitive getConvertedValue(
+ *         ASN1ObjectIdentifier  oid,
  *         String               value)
  *     {
  *         if (str.length() != 0 && str.charAt(0) == '#')
@@ -56,7 +56,7 @@
      * @param off the index at which the encoding starts
      * @return the decoded object
      */
-    protected DERObject convertHexEncoded(
+    protected ASN1Primitive convertHexEncoded(
         String  str,
         int     off)
         throws IOException
@@ -109,5 +109,5 @@
      * @param value the value of the particular DN component.
      * @return the ASN.1 equivalent for the value.
      */
-    public abstract DERObject getConvertedValue(DERObjectIdentifier oid, String value);
+    public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value);
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
index 440e147..32e9346 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
@@ -107,4 +107,4 @@
         index = end;
         return buf.toString().trim();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
index b1e0ed1..ed4dd32 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
@@ -47,6 +47,11 @@
     static final ASN1ObjectIdentifier  id_pe = new ASN1ObjectIdentifier(id_pkix + ".1");
 
     //
+    // ISO ARC for standard certificate and CRL extensions
+    //
+    static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29");
+
+    //
     // authority information access
     //
     static final ASN1ObjectIdentifier  id_ad = new ASN1ObjectIdentifier(id_pkix + ".48");
diff --git a/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
index 7867090..6a97a48 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
@@ -4,17 +4,17 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 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.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
 public class DHDomainParameters
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERInteger p, g, q, j;
+    private ASN1Integer p, g, q, j;
     private DHValidationParms validationParms;
 
     public static DHDomainParameters getInstance(ASN1TaggedObject obj, boolean explicit)
@@ -38,7 +38,7 @@
             + obj.getClass().getName());
     }
 
-    public DHDomainParameters(DERInteger p, DERInteger g, DERInteger q, DERInteger j,
+    public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j,
         DHValidationParms validationParms)
     {
         if (p == null)
@@ -69,45 +69,45 @@
         }
 
         Enumeration e = seq.getObjects();
-        this.p = DERInteger.getInstance(e.nextElement());
-        this.g = DERInteger.getInstance(e.nextElement());
-        this.q = DERInteger.getInstance(e.nextElement());
+        this.p = ASN1Integer.getInstance(e.nextElement());
+        this.g = ASN1Integer.getInstance(e.nextElement());
+        this.q = ASN1Integer.getInstance(e.nextElement());
 
-        DEREncodable next = getNext(e);
+        ASN1Encodable next = getNext(e);
 
-        if (next != null && next instanceof DERInteger)
+        if (next != null && next instanceof ASN1Integer)
         {
-            this.j = DERInteger.getInstance(next);
+            this.j = ASN1Integer.getInstance(next);
             next = getNext(e);
         }
 
         if (next != null)
         {
-            this.validationParms = DHValidationParms.getInstance(next.getDERObject());
+            this.validationParms = DHValidationParms.getInstance(next.toASN1Primitive());
         }
     }
 
-    private static DEREncodable getNext(Enumeration e)
+    private static ASN1Encodable getNext(Enumeration e)
     {
-        return e.hasMoreElements() ? (DEREncodable)e.nextElement() : null;
+        return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null;
     }
 
-    public DERInteger getP()
+    public ASN1Integer getP()
     {
         return this.p;
     }
 
-    public DERInteger getG()
+    public ASN1Integer getG()
     {
         return this.g;
     }
 
-    public DERInteger getQ()
+    public ASN1Integer getQ()
     {
         return this.q;
     }
 
-    public DERInteger getJ()
+    public ASN1Integer getJ()
     {
         return this.j;
     }
@@ -117,7 +117,7 @@
         return this.validationParms;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
         v.add(this.p);
diff --git a/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java b/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
index daafbeb..7c6d217 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
@@ -1,18 +1,18 @@
 package org.bouncycastle.asn1.x9;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 
 public class DHPublicKey
-    extends ASN1Encodable
+    extends ASN1Object
 {
-    private DERInteger y;
+    private ASN1Integer y;
 
     public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit)
     {
-        return getInstance(DERInteger.getInstance(obj, explicit));
+        return getInstance(ASN1Integer.getInstance(obj, explicit));
     }
 
     public static DHPublicKey getInstance(Object obj)
@@ -22,15 +22,15 @@
             return (DHPublicKey)obj;
         }
 
-        if (obj instanceof DERInteger)
+        if (obj instanceof ASN1Integer)
         {
-            return new DHPublicKey((DERInteger)obj);
+            return new DHPublicKey((ASN1Integer)obj);
         }
 
         throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName());
     }
 
-    public DHPublicKey(DERInteger y)
+    public DHPublicKey(ASN1Integer y)
     {
         if (y == null)
         {
@@ -40,12 +40,12 @@
         this.y = y;
     }
 
-    public DERInteger getY()
+    public ASN1Integer getY()
     {
         return this.y;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return this.y;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java b/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
index e801e1c..78b0979 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
@@ -1,18 +1,18 @@
 package org.bouncycastle.asn1.x9;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 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.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
-public class DHValidationParms extends ASN1Encodable
+public class DHValidationParms extends ASN1Object
 {
     private DERBitString seed;
-    private DERInteger pgenCounter;
+    private ASN1Integer pgenCounter;
 
     public static DHValidationParms getInstance(ASN1TaggedObject obj, boolean explicit)
     {
@@ -34,7 +34,7 @@
         throw new IllegalArgumentException("Invalid DHValidationParms: " + obj.getClass().getName());
     }
 
-    public DHValidationParms(DERBitString seed, DERInteger pgenCounter)
+    public DHValidationParms(DERBitString seed, ASN1Integer pgenCounter)
     {
         if (seed == null)
         {
@@ -57,7 +57,7 @@
         }
 
         this.seed = DERBitString.getInstance(seq.getObjectAt(0));
-        this.pgenCounter = DERInteger.getInstance(seq.getObjectAt(1));
+        this.pgenCounter = ASN1Integer.getInstance(seq.getObjectAt(1));
     }
 
     public DERBitString getSeed()
@@ -65,12 +65,12 @@
         return this.seed;
     }
 
-    public DERInteger getPgenCounter()
+    public ASN1Integer getPgenCounter()
     {
         return this.pgenCounter;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
         v.add(this.seed);
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
index bda8dad..06e47b6 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
@@ -1,14 +1,14 @@
 package org.bouncycastle.asn1.x9;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.math.ec.ECCurve;
-import org.bouncycastle.util.Strings;
-import org.bouncycastle.util.encoders.Hex;
-
 import java.math.BigInteger;
 import java.util.Enumeration;
 import java.util.Hashtable;
 
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
 
 /**
  * table of the current named curves defined in X.962 EC-DSA.
@@ -523,7 +523,7 @@
     static final Hashtable curves = new Hashtable();
     static final Hashtable names = new Hashtable();
 
-    static void defineCurve(String name, DERObjectIdentifier oid, X9ECParametersHolder holder)
+    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
     {
         objIds.put(name, oid);
         names.put(oid, name);
@@ -560,7 +560,7 @@
     public static X9ECParameters getByName(
         String name)
     {
-        DERObjectIdentifier oid = (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
 
         if (oid != null)
         {
@@ -577,7 +577,7 @@
      * @param oid an object identifier representing a named curve, if present.
      */
     public static X9ECParameters getByOID(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
 
@@ -595,17 +595,17 @@
      *
      * @return the object identifier associated with name, if present.
      */
-    public static DERObjectIdentifier getOID(
+    public static ASN1ObjectIdentifier getOID(
         String name)
     {
-        return (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
     }
 
     /**
      * return the named curve name represented by the given object identifier.
      */
     public static String getName(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         return (String)names.get(oid);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java b/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
index de35186..1c395d2 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
@@ -1,17 +1,17 @@
 package org.bouncycastle.asn1.x9;
 
 import org.bouncycastle.asn1.ASN1Choice;
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Null;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 
 public class X962Parameters
-    extends ASN1Encodable
+    extends ASN1Object
     implements ASN1Choice
 {
-    private DERObject           params = null;
+    private ASN1Primitive           params = null;
 
     public static X962Parameters getInstance(
         Object obj)
@@ -21,9 +21,9 @@
             return (X962Parameters)obj;
         }
         
-        if (obj instanceof DERObject) 
+        if (obj instanceof ASN1Primitive) 
         {
-            return new X962Parameters((DERObject)obj);
+            return new X962Parameters((ASN1Primitive)obj);
         }
         
         throw new IllegalArgumentException("unknown object in getInstance()");
@@ -39,24 +39,24 @@
     public X962Parameters(
         X9ECParameters      ecParameters)
     {
-        this.params = ecParameters.getDERObject();
+        this.params = ecParameters.toASN1Primitive();
     }
 
     public X962Parameters(
-        DERObjectIdentifier  namedCurve)
+        ASN1ObjectIdentifier  namedCurve)
     {
         this.params = namedCurve;
     }
 
     public X962Parameters(
-        DERObject           obj)
+        ASN1Primitive           obj)
     {
         this.params = obj;
     }
 
     public boolean isNamedCurve()
     {
-        return (params instanceof DERObjectIdentifier);
+        return (params instanceof ASN1ObjectIdentifier);
     }
 
     public boolean isImplicitlyCA()
@@ -64,7 +64,7 @@
         return (params instanceof ASN1Null);
     }
 
-    public DERObject getParameters()
+    public ASN1Primitive getParameters()
     {
         return params;
     }
@@ -79,8 +79,8 @@
      * }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        return params;
+        return (ASN1Primitive)params;
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
index 8f46c07..5c5afdb 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
@@ -2,14 +2,14 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.math.ec.ECCurve;
 
@@ -18,12 +18,12 @@
  * X9.62, for further details.
  */
 public class X9Curve
-    extends ASN1Encodable
+    extends ASN1Object
     implements X9ObjectIdentifiers
 {
     private ECCurve     curve;
     private byte[]      seed;
-    private DERObjectIdentifier fieldIdentifier = null;
+    private ASN1ObjectIdentifier fieldIdentifier = null;
 
     public X9Curve(
         ECCurve     curve)
@@ -49,7 +49,7 @@
         fieldIdentifier = fieldID.getIdentifier();
         if (fieldIdentifier.equals(prime_field))
         {
-            BigInteger      p = ((DERInteger)fieldID.getParameters()).getValue();
+            BigInteger      p = ((ASN1Integer)fieldID.getParameters()).getValue();
             X9FieldElement  x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0));
             X9FieldElement  x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1));
             curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
@@ -59,11 +59,11 @@
             if (fieldIdentifier.equals(characteristic_two_field)) 
             {
                 // Characteristic two field
-                DERSequence parameters = (DERSequence)fieldID.getParameters();
-                int m = ((DERInteger)parameters.getObjectAt(0)).getValue().
+                ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters());
+                int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue().
                     intValue();
-                DERObjectIdentifier representation
-                    = (DERObjectIdentifier)parameters.getObjectAt(1);
+                ASN1ObjectIdentifier representation
+                    = (ASN1ObjectIdentifier)parameters.getObjectAt(1);
 
                 int k1 = 0;
                 int k2 = 0;
@@ -71,7 +71,7 @@
                 if (representation.equals(tpBasis)) 
                 {
                     // Trinomial basis representation
-                    k1 = ((DERInteger)parameters.getObjectAt(2)).getValue().
+                    k1 = ((ASN1Integer)parameters.getObjectAt(2)).getValue().
                         intValue();
                 }
                 else 
@@ -79,11 +79,11 @@
                     // Pentanomial basis representation
                     DERSequence pentanomial
                         = (DERSequence)parameters.getObjectAt(2);
-                    k1 = ((DERInteger)pentanomial.getObjectAt(0)).getValue().
+                    k1 = ((ASN1Integer)pentanomial.getObjectAt(0)).getValue().
                         intValue();
-                    k2 = ((DERInteger)pentanomial.getObjectAt(1)).getValue().
+                    k2 = ((ASN1Integer)pentanomial.getObjectAt(1)).getValue().
                         intValue();
-                    k3 = ((DERInteger)pentanomial.getObjectAt(2)).getValue().
+                    k3 = ((ASN1Integer)pentanomial.getObjectAt(2)).getValue().
                         intValue();
                 }
                 X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0));
@@ -136,19 +136,19 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
         if (fieldIdentifier.equals(prime_field)) 
         { 
-            v.add(new X9FieldElement(curve.getA()).getDERObject());
-            v.add(new X9FieldElement(curve.getB()).getDERObject());
+            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
+            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
         } 
         else if (fieldIdentifier.equals(characteristic_two_field)) 
         {
-            v.add(new X9FieldElement(curve.getA()).getDERObject());
-            v.add(new X9FieldElement(curve.getB()).getDERObject());
+            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
+            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
         }
 
         if (seed != null)
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
index c3b0d66..e059089 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
@@ -1,23 +1,23 @@
 package org.bouncycastle.asn1.x9;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import java.math.BigInteger;
+
 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.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.math.ec.ECCurve;
 import org.bouncycastle.math.ec.ECPoint;
 
-import java.math.BigInteger;
-
 /**
  * ASN.1 def for Elliptic-Curve ECParameters structure. See
  * X9.62, for further details.
  */
 public class X9ECParameters
-    extends ASN1Encodable
+    extends ASN1Object
     implements X9ObjectIdentifiers
 {
     private static final BigInteger   ONE = BigInteger.valueOf(1);
@@ -29,11 +29,11 @@
     private BigInteger          h;
     private byte[]              seed;
 
-    public X9ECParameters(
+    private X9ECParameters(
         ASN1Sequence  seq)
     {
-        if (!(seq.getObjectAt(0) instanceof DERInteger)
-           || !((DERInteger)seq.getObjectAt(0)).getValue().equals(ONE))
+        if (!(seq.getObjectAt(0) instanceof ASN1Integer)
+           || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE))
         {
             throw new IllegalArgumentException("bad version in X9ECParameters");
         }
@@ -44,15 +44,30 @@
 
         this.curve = x9c.getCurve();
         this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint();
-        this.n = ((DERInteger)seq.getObjectAt(4)).getValue();
+        this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();
         this.seed = x9c.getSeed();
 
         if (seq.size() == 6)
         {
-            this.h = ((DERInteger)seq.getObjectAt(5)).getValue();
+            this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();
         }
     }
 
+    public static X9ECParameters getInstance(Object obj)
+    {
+        if (obj instanceof X9ECParameters)
+        {
+            return (X9ECParameters)obj;
+        }
+
+        if (obj != null)
+        {
+            return new X9ECParameters(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
     public X9ECParameters(
         ECCurve     curve,
         ECPoint     g,
@@ -141,19 +156,19 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new DERInteger(1));
+        v.add(new ASN1Integer(1));
         v.add(fieldID);
         v.add(new X9Curve(curve, seed));
         v.add(new X9ECPoint(g));
-        v.add(new DERInteger(n));
+        v.add(new ASN1Integer(n));
 
         if (h != null)
         {
-            v.add(new DERInteger(h));
+            v.add(new ASN1Integer(h));
         }
 
         return new DERSequence(v);
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
index 470b3d6..a4acb6e 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -1,8 +1,8 @@
 package org.bouncycastle.asn1.x9;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
-import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.math.ec.ECCurve;
 import org.bouncycastle.math.ec.ECPoint;
@@ -11,7 +11,7 @@
  * class for describing an ECPoint as a DER object.
  */
 public class X9ECPoint
-    extends ASN1Encodable
+    extends ASN1Object
 {
     ECPoint p;
 
@@ -41,7 +41,7 @@
      * <p>
      * Octet string produced using ECPoint.getEncoded().
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         return new DEROctetString(p.getEncoded());
     }
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java b/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
index 2173d2a..13fe772 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
@@ -2,9 +2,9 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
-import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.math.ec.ECFieldElement;
 
@@ -12,7 +12,7 @@
  * class for processing an FieldElement as a DER object.
  */
 public class X9FieldElement
-    extends ASN1Encodable
+    extends ASN1Object
 {
     protected ECFieldElement  f;
     
@@ -54,7 +54,7 @@
      * </li>
      * </ol>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         int byteCount = converter.getByteLength(f);
         byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount);
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
index c2c2ef9..30598e2 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
@@ -2,12 +2,12 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
 /**
@@ -15,11 +15,11 @@
  * X9.62, for further details.
  */
 public class X9FieldID
-    extends ASN1Encodable
+    extends ASN1Object
     implements X9ObjectIdentifiers
 {
-    private DERObjectIdentifier     id;
-    private DERObject               parameters;
+    private ASN1ObjectIdentifier     id;
+    private ASN1Primitive parameters;
 
     /**
      * Constructor for elliptic curves over prime fields
@@ -29,7 +29,7 @@
     public X9FieldID(BigInteger primeP)
     {
         this.id = prime_field;
-        this.parameters = new DERInteger(primeP);
+        this.parameters = new ASN1Integer(primeP);
     }
 
     /**
@@ -51,20 +51,20 @@
     {
         this.id = characteristic_two_field;
         ASN1EncodableVector fieldIdParams = new ASN1EncodableVector();
-        fieldIdParams.add(new DERInteger(m));
+        fieldIdParams.add(new ASN1Integer(m));
         
         if (k2 == 0) 
         {
             fieldIdParams.add(tpBasis);
-            fieldIdParams.add(new DERInteger(k1));
+            fieldIdParams.add(new ASN1Integer(k1));
         } 
         else 
         {
             fieldIdParams.add(ppBasis);
             ASN1EncodableVector pentanomialParams = new ASN1EncodableVector();
-            pentanomialParams.add(new DERInteger(k1));
-            pentanomialParams.add(new DERInteger(k2));
-            pentanomialParams.add(new DERInteger(k3));
+            pentanomialParams.add(new ASN1Integer(k1));
+            pentanomialParams.add(new ASN1Integer(k2));
+            pentanomialParams.add(new ASN1Integer(k3));
             fieldIdParams.add(new DERSequence(pentanomialParams));
         }
         
@@ -74,16 +74,16 @@
     public X9FieldID(
         ASN1Sequence  seq)
     {
-        this.id = (DERObjectIdentifier)seq.getObjectAt(0);
-        this.parameters = (DERObject)seq.getObjectAt(1);
+        this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        this.parameters = (ASN1Primitive)seq.getObjectAt(1);
     }
 
-    public DERObjectIdentifier getIdentifier()
+    public ASN1ObjectIdentifier getIdentifier()
     {
         return id;
     }
 
-    public DERObject getParameters()
+    public ASN1Primitive getParameters()
     {
         return parameters;
     }
@@ -97,7 +97,7 @@
      *  }
      * </pre>
      */
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java b/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
index ae820ab..16a803c 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
@@ -1,10 +1,10 @@
 package org.bouncycastle.asn1.x9;
 
+import java.math.BigInteger;
+
 import org.bouncycastle.math.ec.ECCurve;
 import org.bouncycastle.math.ec.ECFieldElement;
 
-import java.math.BigInteger;
-
 public class X9IntegerConverter
 {
     public int getByteLength(
diff --git a/src/main/java/org/bouncycastle/crypto/CryptoException.java b/src/main/java/org/bouncycastle/crypto/CryptoException.java
index dc4a8df..352c556 100644
--- a/src/main/java/org/bouncycastle/crypto/CryptoException.java
+++ b/src/main/java/org/bouncycastle/crypto/CryptoException.java
@@ -6,6 +6,8 @@
 public class CryptoException 
     extends Exception
 {
+    private Throwable cause;
+
     /**
      * base constructor.
      */
@@ -23,4 +25,24 @@
     {
         super(message);
     }
+
+    /**
+     * Create a CryptoException with the given message and underlying cause.
+     *
+     * @param message message describing exception.
+     * @param cause the throwable that was the underlying cause.
+     */
+    public CryptoException(
+        String  message,
+        Throwable cause)
+    {
+        super(message);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
index ae4ffdc..dbf550d 100644
--- a/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
@@ -97,7 +97,7 @@
      * converts a password to a byte array according to the scheme in
      * PKCS5 (ascii, no padding)
      *
-     * @param password a character array reqpresenting the password.
+     * @param password a character array representing the password.
      * @return a byte array representing the password.
      */
     public static byte[] PKCS5PasswordToBytes(
@@ -117,7 +117,7 @@
      * converts a password to a byte array according to the scheme in
      * PKCS5 (UTF-8, no padding)
      *
-     * @param password a character array reqpresenting the password.
+     * @param password a character array representing the password.
      * @return a byte array representing the password.
      */
     public static byte[] PKCS5PasswordToUTF8Bytes(
diff --git a/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java b/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
deleted file mode 100644
index ec91e1a..0000000
--- a/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
+++ /dev/null
@@ -1,287 +0,0 @@
-package org.bouncycastle.crypto.encodings;
-
-import java.math.BigInteger;
-
-import org.bouncycastle.crypto.AsymmetricBlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.crypto.params.RSAKeyParameters;
-
-/**
- * ISO 9796-1 padding. Note in the light of recent results you should
- * only use this with RSA (rather than the "simpler" Rabin keys) and you
- * should never use it with anything other than a hash (ie. even if the
- * message is small don't sign the message, sign it's hash) or some "random"
- * value. See your favorite search engine for details.
- */
-public class ISO9796d1Encoding
-    implements AsymmetricBlockCipher
-{
-    private static final BigInteger SIXTEEN = BigInteger.valueOf(16L);
-    private static final BigInteger SIX     = BigInteger.valueOf(6L);
-
-    private static byte[]    shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
-                                    0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
-    private static byte[]    inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
-                                    0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
-
-    private AsymmetricBlockCipher   engine;
-    private boolean                 forEncryption;
-    private int                     bitSize;
-    private int                     padBits = 0;
-    private BigInteger              modulus;
-
-    public ISO9796d1Encoding(
-        AsymmetricBlockCipher   cipher)
-    {
-        this.engine = cipher;
-    }
-
-    public AsymmetricBlockCipher getUnderlyingCipher()
-    {
-        return engine;
-    }
-
-    public void init(
-        boolean             forEncryption,
-        CipherParameters    param)
-    {
-        RSAKeyParameters  kParam = null;
-
-        if (param instanceof ParametersWithRandom)
-        {
-            ParametersWithRandom    rParam = (ParametersWithRandom)param;
-
-            kParam = (RSAKeyParameters)rParam.getParameters();
-        }
-        else
-        {
-            kParam = (RSAKeyParameters)param;
-        }
-
-        engine.init(forEncryption, param);
-
-        modulus = kParam.getModulus();
-        bitSize = modulus.bitLength();
-
-        this.forEncryption = forEncryption;
-    }
-
-    /**
-     * return the input block size. The largest message we can process
-     * is (key_size_in_bits + 3)/16, which in our world comes to
-     * key_size_in_bytes / 2.
-     */
-    public int getInputBlockSize()
-    {
-        int     baseBlockSize = engine.getInputBlockSize();
-
-        if (forEncryption)
-        {
-            return (baseBlockSize + 1) / 2;
-        }
-        else
-        {
-            return baseBlockSize;
-        }
-    }
-
-    /**
-     * return the maximum possible size for the output.
-     */
-    public int getOutputBlockSize()
-    {
-        int     baseBlockSize = engine.getOutputBlockSize();
-
-        if (forEncryption)
-        {
-            return baseBlockSize;
-        }
-        else
-        {
-            return (baseBlockSize + 1) / 2;
-        }
-    }
-
-    /**
-     * set the number of bits in the next message to be treated as
-     * pad bits.
-     */
-    public void setPadBits(
-        int     padBits)
-    {
-        if (padBits > 7)
-        {
-            throw new IllegalArgumentException("padBits > 7");
-        }
-
-        this.padBits = padBits;
-    }
-
-    /**
-     * retrieve the number of pad bits in the last decoded message.
-     */
-    public int getPadBits()
-    {
-        return padBits;
-    }
-
-    public byte[] processBlock(
-        byte[]  in,
-        int     inOff,
-        int     inLen)
-        throws InvalidCipherTextException
-    {
-        if (forEncryption)
-        {
-            return encodeBlock(in, inOff, inLen);
-        }
-        else
-        {
-            return decodeBlock(in, inOff, inLen);
-        }
-    }
-
-    private byte[] encodeBlock(
-        byte[]  in,
-        int     inOff,
-        int     inLen)
-        throws InvalidCipherTextException
-    {
-        byte[]  block = new byte[(bitSize + 7) / 8];
-        int     r = padBits + 1;
-        int     z = inLen;
-        int     t = (bitSize + 13) / 16;
-
-        for (int i = 0; i < t; i += z)
-        {
-            if (i > t - z)
-            {
-                System.arraycopy(in, inOff + inLen - (t - i),
-                                    block, block.length - t, t - i);
-            }
-            else
-            {
-                System.arraycopy(in, inOff, block, block.length - (i + z), z);
-            }
-        }
-
-        for (int i = block.length - 2 * t; i != block.length; i += 2)
-        {
-            byte    val = block[block.length - t + i / 2];
-
-            block[i] = (byte)((shadows[(val & 0xff) >>> 4] << 4)
-                                                | shadows[val & 0x0f]);
-            block[i + 1] = val;
-        }
-
-        block[block.length - 2 * z] ^= r;
-        block[block.length - 1] = (byte)((block[block.length - 1] << 4) | 0x06);
-
-        int maxBit = (8 - (bitSize - 1) % 8);
-        int offSet = 0;
-
-        if (maxBit != 8)
-        {
-            block[0] &= 0xff >>> maxBit;
-            block[0] |= 0x80 >>> maxBit;
-        }
-        else
-        {
-            block[0] = 0x00;
-            block[1] |= 0x80;
-            offSet = 1;
-        }
-
-        return engine.processBlock(block, offSet, block.length - offSet);
-    }
-
-    /**
-     * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
-     */
-    private byte[] decodeBlock(
-        byte[]  in,
-        int     inOff,
-        int     inLen)
-        throws InvalidCipherTextException
-    {
-        byte[]  block = engine.processBlock(in, inOff, inLen);
-        int     r = 1;
-        int     t = (bitSize + 13) / 16;
-
-        BigInteger iS = new BigInteger(1, block);
-        BigInteger iR;
-        if (iS.mod(SIXTEEN).equals(SIX))
-        {
-            iR = iS;
-        }
-        else if ((modulus.subtract(iS)).mod(SIXTEEN).equals(SIX))
-        {
-            iR = modulus.subtract(iS);
-        }
-        else
-        {
-            throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16");
-        }
-
-        block = convertOutputDecryptOnly(iR);
-
-        if ((block[block.length - 1] & 0x0f) != 0x6 )
-        {
-            throw new InvalidCipherTextException("invalid forcing byte in block");
-        }
-
-        block[block.length - 1] = (byte)(((block[block.length - 1] & 0xff) >>> 4) | ((inverse[(block[block.length - 2] & 0xff) >> 4]) << 4));
-        block[0] = (byte)((shadows[(block[1] & 0xff) >>> 4] << 4)
-                                                | shadows[block[1] & 0x0f]);
-
-        boolean boundaryFound = false;
-        int     boundary = 0;
-
-        for (int i = block.length - 1; i >= block.length - 2 * t; i -= 2)
-        {
-            int val = ((shadows[(block[i] & 0xff) >>> 4] << 4)
-                                        | shadows[block[i] & 0x0f]);
-
-            if (((block[i - 1] ^ val) & 0xff) != 0)
-            {
-                if (!boundaryFound)
-                {
-                    boundaryFound = true;
-                    r = (block[i - 1] ^ val) & 0xff;
-                    boundary = i - 1;
-                }
-                else
-                {
-                    throw new InvalidCipherTextException("invalid tsums in block");
-                }
-            }
-        }
-
-        block[boundary] = 0;
-
-        byte[]  nblock = new byte[(block.length - boundary) / 2];
-
-        for (int i = 0; i < nblock.length; i++)
-        {
-            nblock[i] = block[2 * i + boundary + 1];
-        }
-
-        padBits = r - 1;
-
-        return nblock;
-    }
-
-    private static byte[] convertOutputDecryptOnly(BigInteger result)
-    {
-        byte[] output = result.toByteArray();
-        if (output[0] == 0) // have ended up with an extra zero byte, copy down.
-        {
-            byte[] tmp = new byte[output.length - 1];
-            System.arraycopy(output, 1, tmp, 0, tmp.length);
-            return tmp;
-        }
-        return output;
-    }
-}
diff --git a/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
index 9e94d77..fb11fc5 100644
--- a/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
+++ b/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
@@ -4,7 +4,9 @@
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.digests.SHA1Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 import org.bouncycastle.crypto.params.ParametersWithRandom;
 
 import java.security.SecureRandom;
@@ -26,7 +28,9 @@
     public OAEPEncoding(
         AsymmetricBlockCipher   cipher)
     {
-        this(cipher, new SHA1Digest(), null);
+        // BEGIN android-changed
+        this(cipher, new OpenSSLDigest.SHA1(), null);
+        // END android-changed
     }
     
     public OAEPEncoding(
diff --git a/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
index a6a5986..8bcfe26 100644
--- a/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
+++ b/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
@@ -206,6 +206,12 @@
         {
             throw new InvalidCipherTextException("unknown block type");
         }
+        // BEGIN android-added
+        if ((type == 1 && forPrivateKey) || (type == 2 && !forPrivateKey))
+        {
+            throw new InvalidCipherTextException("invalid block type " + type);
+        }
+        // END android-added
 
         if (useStrictLength && block.length != engine.getOutputBlockSize())
         {
diff --git a/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java b/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
index f915434..d1935ec 100644
--- a/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
+++ b/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
@@ -44,9 +44,9 @@
 
         byte[] keyMaster = ((KeyParameter)params).getKey();
 
-        if (keyMaster.length > 24)
+        if (keyMaster.length != 24 && keyMaster.length != 16)
         {
-            throw new IllegalArgumentException("key size greater than 24 bytes");
+            throw new IllegalArgumentException("key size must be 16 or 24 bytes.");
         }
 
         this.forEncryption = encrypting;
diff --git a/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
index a3c72cc..be2d09b 100644
--- a/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
+++ b/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
@@ -6,7 +6,9 @@
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.InvalidCipherTextException;
 import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.digests.SHA1Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 import org.bouncycastle.crypto.modes.CBCBlockCipher;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -52,7 +54,9 @@
     //
     // checksum digest
     //
-    Digest  sha1 = new SHA1Digest();
+    // BEGIN android-changed
+    Digest  sha1 = new OpenSSLDigest.SHA1();
+    // END android-changed
     byte[]  digest = new byte[20];
 
    /**
diff --git a/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java b/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java
index e5a9bb3..62240ea 100644
--- a/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java
+++ b/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java
@@ -313,4 +313,4 @@
         out[outOff + 6] = (byte)x76;
         out[outOff + 7] = (byte)(x76 >> 8);
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java b/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java
index adb908e..bf43ff2 100644
--- a/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java
+++ b/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java
@@ -402,17 +402,19 @@
                     gSBox[i*2+0x200] = gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)];
                     gSBox[i*2+0x201] = gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
                 break;
-                case 0: /* 256 bits of key */
+                case 0: // 256 bits of key
                     b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
                     b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
                     b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
                     b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
-                case 3: 
+                    // fall through, having pre-processed b[0]..b[3] with k32[3]
+                case 3: // 192 bits of key
                     b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
                     b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
                     b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
                     b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
-                case 2:
+                    // fall through, having pre-processed b[0]..b[3] with k32[2]
+                case 2: // 128 bits of key
                     gSBox[i*2]   = gMDS0[(P[P_01]
                         [(P[P_02][b0] & 0xff) ^ b0(k1)] & 0xff) ^ b0(k0)];
                     gSBox[i*2+1] = gMDS1[(P[P_11]
diff --git a/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
index be977d7..f05f3d7 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -1,8 +1,9 @@
 package org.bouncycastle.crypto.generators;
 
 import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 import org.bouncycastle.crypto.params.DSAParameters;
 import org.bouncycastle.crypto.params.DSAValidationParameters;
 import org.bouncycastle.util.Arrays;
@@ -75,7 +76,9 @@
         byte[]          part1 = new byte[20];
         byte[]          part2 = new byte[20];
         byte[]          u = new byte[20];
-        SHA1Digest      sha1 = new SHA1Digest();
+        // BEGIN android-changed
+        Digest          sha1 = new OpenSSLDigest.SHA1();
+        // END android-changed
         int             n = (L - 1) / 160;
         byte[]          w = new byte[L / 8];
 
@@ -166,7 +169,9 @@
     {
 // A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
         // FIXME This should be configurable (digest size in bits must be >= N)
-        Digest d = new SHA256Digest();
+        // BEGIN android-changed
+        Digest d = new OpenSSLDigest.SHA256();
+        // END android-changed
         int outlen = d.getDigestSize() * 8;
 
 // 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
diff --git a/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
index 8a4d28a..6999653 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
@@ -3,7 +3,9 @@
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.PBEParametersGenerator;
-import org.bouncycastle.crypto.digests.MD5Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
 
@@ -17,7 +19,9 @@
 public class OpenSSLPBEParametersGenerator
     extends PBEParametersGenerator
 {
-    private Digest  digest = new MD5Digest();
+    // BEGIN android-changed
+    private Digest  digest = new OpenSSLDigest.MD5();
+    // END android-changed
 
     /**
      * Construct a OpenSSL Parameters generator. 
diff --git a/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
index bf2f368..8fb1cc8 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
@@ -133,7 +133,7 @@
             digest.update(D, 0, D.length);
             digest.update(I, 0, I.length);
             digest.doFinal(A, 0);
-            for (int j = 1; j != iterationCount; j++)
+            for (int j = 1; j < iterationCount; j++)
             {
                 digest.update(A, 0, A.length);
                 digest.doFinal(A, 0);
diff --git a/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
index 9b4972d..236ae2e 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -1,9 +1,12 @@
 package org.bouncycastle.crypto.generators;
 
 import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.Mac;
 import org.bouncycastle.crypto.PBEParametersGenerator;
-import org.bouncycastle.crypto.digests.SHA1Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-changed
 import org.bouncycastle.crypto.macs.HMac;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -19,13 +22,21 @@
 public class PKCS5S2ParametersGenerator
     extends PBEParametersGenerator
 {
-    private Mac    hMac = new HMac(new SHA1Digest());
+    private Mac hMac;
 
     /**
      * construct a PKCS5 Scheme 2 Parameters generator.
      */
     public PKCS5S2ParametersGenerator()
     {
+        // BEGIN android-changed
+    	this(new OpenSSLDigest.SHA1());
+        // END android-changed
+    }
+
+    public PKCS5S2ParametersGenerator(Digest digest)
+    {
+        hMac = new HMac(digest);
     }
 
     private void F(
diff --git a/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
new file mode 100644
index 0000000..bb09a76
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
@@ -0,0 +1,244 @@
+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/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
new file mode 100644
index 0000000..17a7b6d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
@@ -0,0 +1,188 @@
+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/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java b/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
index 2907954..23c7e53 100644
--- a/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
+++ b/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
@@ -1,29 +1,25 @@
 package org.bouncycastle.crypto.io;
 
-import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
 import org.bouncycastle.crypto.Digest;
 
 public class DigestOutputStream
-    extends FilterOutputStream
+    extends OutputStream
 {
     protected Digest digest;
 
     public DigestOutputStream(
-        OutputStream    stream,
-        Digest          digest)
+        Digest          Digest)
     {
-        super(stream);
-        this.digest = digest;
+        this.digest = Digest;
     }
 
     public void write(int b)
         throws IOException
     {
         digest.update((byte)b);
-        out.write(b);
     }
 
     public void write(
@@ -33,11 +29,14 @@
         throws IOException
     {
         digest.update(b, off, len);
-        out.write(b, off, len);
     }
 
-    public Digest getDigest()
+    public byte[] getDigest()
     {
-        return digest;
+        byte[] res = new byte[digest.getDigestSize()];
+        
+        digest.doFinal(res, 0);
+        
+        return res;
     }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java b/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
index 2cac1c3..0f0e7db 100644
--- a/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
+++ b/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
@@ -1,21 +1,18 @@
 package org.bouncycastle.crypto.io;
 
-import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
 import org.bouncycastle.crypto.Mac;
 
 public class MacOutputStream
-    extends FilterOutputStream
+    extends OutputStream
 {
     protected Mac mac;
 
     public MacOutputStream(
-        OutputStream stream,
         Mac          mac)
     {
-        super(stream);
         this.mac = mac;
     }
 
@@ -23,7 +20,6 @@
         throws IOException
     {
         mac.update((byte)b);
-        out.write(b);
     }
 
     public void write(
@@ -33,12 +29,14 @@
         throws IOException
     {
         mac.update(b, off, len);
-        out.write(b, off, len);
     }
 
-    public Mac getMac()
+    public byte[] getMac()
     {
-        return mac;
+        byte[] res = new byte[mac.getMacSize()];
+
+        mac.doFinal(res, 0);
+
+        return res;
     }
 }
-
diff --git a/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/src/main/java/org/bouncycastle/crypto/macs/HMac.java
index 7272f32..c0c8333 100644
--- a/src/main/java/org/bouncycastle/crypto/macs/HMac.java
+++ b/src/main/java/org/bouncycastle/crypto/macs/HMac.java
@@ -32,23 +32,31 @@
     {
         blockLengths = new Hashtable();
         
-        blockLengths.put("GOST3411", Integer.valueOf(32));
-        
-        blockLengths.put("MD2", Integer.valueOf(16));
-        blockLengths.put("MD4", Integer.valueOf(64));
+        // BEGIN android-removed
+        // blockLengths.put("GOST3411", Integer.valueOf(32));
+        //
+        // blockLengths.put("MD2", Integer.valueOf(16));
+        // blockLengths.put("MD4", Integer.valueOf(64));
+        // END android-removed
         blockLengths.put("MD5", Integer.valueOf(64));
         
-        blockLengths.put("RIPEMD128", Integer.valueOf(64));
-        blockLengths.put("RIPEMD160", Integer.valueOf(64));
+        // BEGIN android-removed
+        // blockLengths.put("RIPEMD128", Integer.valueOf(64));
+        // blockLengths.put("RIPEMD160", Integer.valueOf(64));
+        // END android-removed
         
         blockLengths.put("SHA-1", Integer.valueOf(64));
-        blockLengths.put("SHA-224", Integer.valueOf(64));
+        // BEGIN android-removed
+        // blockLengths.put("SHA-224", Integer.valueOf(64));
+        // END android-removed
         blockLengths.put("SHA-256", Integer.valueOf(64));
         blockLengths.put("SHA-384", Integer.valueOf(128));
         blockLengths.put("SHA-512", Integer.valueOf(128));
         
-        blockLengths.put("Tiger", Integer.valueOf(64));
-        blockLengths.put("Whirlpool", Integer.valueOf(64));
+        // BEGIN android-removed
+        // blockLengths.put("Tiger", Integer.valueOf(64));
+        // blockLengths.put("Whirlpool", Integer.valueOf(64));
+        // END android-removed
     }
     
     private static int getByteLength(
diff --git a/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
index f75c546..1219f6d 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
@@ -61,29 +61,47 @@
         CipherParameters    params)
         throws IllegalArgumentException
     {
+        boolean oldEncrypting = this.encrypting;
+
         this.encrypting = encrypting;
-        
+
         if (params instanceof ParametersWithIV)
         {
-                ParametersWithIV ivParam = (ParametersWithIV)params;
-                byte[]      iv = ivParam.getIV();
+            ParametersWithIV ivParam = (ParametersWithIV)params;
+            byte[] iv = ivParam.getIV();
 
-                if (iv.length != blockSize)
-                {
-                    throw new IllegalArgumentException("initialisation vector must be the same length as block size");
-                }
+            if (iv.length != blockSize)
+            {
+                throw new IllegalArgumentException("initialisation vector must be the same length as block size");
+            }
 
-                System.arraycopy(iv, 0, IV, 0, iv.length);
+            System.arraycopy(iv, 0, IV, 0, iv.length);
 
-                reset();
+            reset();
 
+            // if null it's an IV changed only.
+            if (ivParam.getParameters() != null)
+            {
                 cipher.init(encrypting, ivParam.getParameters());
+            }
+            else if (oldEncrypting != encrypting)
+            {
+                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+            }
         }
         else
         {
-                reset();
+            reset();
 
+            // if it;s null key is to be reused.
+            if (params != null)
+            {
                 cipher.init(encrypting, params);
+            }
+            else if (oldEncrypting != encrypting)
+            {
+                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+            }
         }
     }
 
diff --git a/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
index 0de0450..0af49f4 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
@@ -87,7 +87,11 @@
 
                 reset();
 
-                cipher.init(true, ivParam.getParameters());
+                // if null it's an IV changed only.
+                if (ivParam.getParameters() != null)
+                {
+                    cipher.init(true, ivParam.getParameters());
+                }
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index 8e7c315..7c98efa 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -31,7 +31,6 @@
     private int                 macSize;
     private byte[]              nonce;
     private byte[]              A;
-    private KeyParameter        keyParam;
     private byte[]              H;
     private byte[]              initS;
     private byte[]              J0;
@@ -83,6 +82,8 @@
         this.forEncryption = forEncryption;
         this.macBlock = null;
 
+        KeyParameter        keyParam;
+
         if (params instanceof AEADParameters)
         {
             AEADParameters param = (AEADParameters)params;
@@ -128,7 +129,11 @@
         }
 
         // Cipher always used in forward mode
-        cipher.init(true, keyParam);
+        // if keyParam is null we're reusing the last key.
+        if (keyParam != null)
+        {
+            cipher.init(true, keyParam);
+        }
 
         // TODO This should be configurable by init parameters
         // (but must be 16 if nonce length not 12) (BLOCK_SIZE?)
diff --git a/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java
deleted file mode 100644
index 3886341..0000000
--- a/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package org.bouncycastle.crypto.modes;
-
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.params.ParametersWithIV;
-
-/**
- * implements the GOST 28147 OFB counter mode (GCTR).
- */
-public class GOFBBlockCipher
-    implements BlockCipher
-{
-    private byte[]          IV;
-    private byte[]          ofbV;
-    private byte[]          ofbOutV;
-
-    private final int             blockSize;
-    private final BlockCipher     cipher;
-
-    boolean firstStep = true;
-    int N3;
-    int N4;
-    static final int C1 = 16843012; //00000001000000010000000100000100
-    static final int C2 = 16843009; //00000001000000010000000100000001
-
-
-    /**
-     * Basic constructor.
-     *
-     * @param cipher the block cipher to be used as the basis of the
-     * counter mode (must have a 64 bit block size).
-     */
-    public GOFBBlockCipher(
-        BlockCipher cipher)
-    {
-        this.cipher = cipher;
-        this.blockSize = cipher.getBlockSize();
-        
-        if (blockSize != 8)
-        {
-            throw new IllegalArgumentException("GCTR only for 64 bit block ciphers");
-        }
-
-        this.IV = new byte[cipher.getBlockSize()];
-        this.ofbV = new byte[cipher.getBlockSize()];
-        this.ofbOutV = new byte[cipher.getBlockSize()];
-    }
-
-    /**
-     * return the underlying block cipher that we are wrapping.
-     *
-     * @return the underlying block cipher that we are wrapping.
-     */
-    public BlockCipher getUnderlyingCipher()
-    {
-        return cipher;
-    }
-
-    /**
-     * Initialise the cipher and, possibly, the initialisation vector (IV).
-     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
-     * An IV which is too short is handled in FIPS compliant fashion.
-     *
-     * @param encrypting if true the cipher is initialised for
-     *  encryption, if false for decryption.
-     * @param params the key and other data required by the cipher.
-     * @exception IllegalArgumentException if the params argument is
-     * inappropriate.
-     */
-    public void init(
-        boolean             encrypting, //ignored by this CTR mode
-        CipherParameters    params)
-        throws IllegalArgumentException
-    {
-        firstStep = true;
-        N3 = 0;
-        N4 = 0;
-
-        if (params instanceof ParametersWithIV)
-        {
-                ParametersWithIV ivParam = (ParametersWithIV)params;
-                byte[]      iv = ivParam.getIV();
-
-                if (iv.length < IV.length)
-                {
-                    // prepend the supplied IV with zeros (per FIPS PUB 81)
-                    System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); 
-                    for (int i = 0; i < IV.length - iv.length; i++)
-                    {
-                        IV[i] = 0;
-                    }
-                }
-                else
-                {
-                    System.arraycopy(iv, 0, IV, 0, IV.length);
-                }
-
-                reset();
-
-                cipher.init(true, ivParam.getParameters());
-        }
-        else
-        {
-                reset();
-
-                cipher.init(true, params);
-        }
-    }
-
-    /**
-     * return the algorithm name and mode.
-     *
-     * @return the name of the underlying algorithm followed by "/GCTR"
-     * and the block size in bits
-     */
-    public String getAlgorithmName()
-    {
-        return cipher.getAlgorithmName() + "/GCTR";
-    }
-
-    
-    /**
-     * return the block size we are operating at (in bytes).
-     *
-     * @return the block size we are operating at (in bytes).
-     */
-    public int getBlockSize()
-    {
-        return blockSize;
-    }
-
-    /**
-     * Process one block of input from the array in and write it to
-     * the out array.
-     *
-     * @param in the array containing the input data.
-     * @param inOff offset into the in array the data starts at.
-     * @param out the array the output data will be copied into.
-     * @param outOff the offset into the out array the output will start at.
-     * @exception DataLengthException if there isn't enough data in in, or
-     * space in out.
-     * @exception IllegalStateException if the cipher isn't initialised.
-     * @return the number of bytes processed and produced.
-     */
-    public int processBlock(
-        byte[]      in,
-        int         inOff,
-        byte[]      out,
-        int         outOff)
-        throws DataLengthException, IllegalStateException
-    {
-        if ((inOff + blockSize) > in.length)
-        {
-            throw new DataLengthException("input buffer too short");
-        }
-
-        if ((outOff + blockSize) > out.length)
-        {
-            throw new DataLengthException("output buffer too short");
-        }
-
-        if (firstStep)
-        {
-            firstStep = false;
-            cipher.processBlock(ofbV, 0, ofbOutV, 0);
-            N3 = bytesToint(ofbOutV, 0);
-            N4 = bytesToint(ofbOutV, 4);
-        }
-        N3 += C2;
-        N4 += C1;
-        intTobytes(N3, ofbV, 0);
-        intTobytes(N4, ofbV, 4);
-
-        cipher.processBlock(ofbV, 0, ofbOutV, 0);
-
-        //
-        // XOR the ofbV with the plaintext producing the cipher text (and
-        // the next input block).
-        //
-        for (int i = 0; i < blockSize; i++)
-        {
-            out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
-        }
-
-        //
-        // change over the input block.
-        //
-        System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
-        System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
-
-        return blockSize;
-    }
-
-    /**
-     * reset the feedback vector back to the IV and reset the underlying
-     * cipher.
-     */
-    public void reset()
-    {
-        System.arraycopy(IV, 0, ofbV, 0, IV.length);
-
-        cipher.reset();
-    }
-
-    //array of bytes to type int
-    private int bytesToint(
-        byte[]  in,
-        int     inOff)
-    {
-        return  ((in[inOff + 3] << 24) & 0xff000000) + ((in[inOff + 2] << 16) & 0xff0000) +
-                ((in[inOff + 1] << 8) & 0xff00) + (in[inOff] & 0xff);
-    }
-
-    //int to array of bytes
-    private void intTobytes(
-            int     num,
-            byte[]  out,
-            int     outOff)
-    {
-            out[outOff + 3] = (byte)(num >>> 24);
-            out[outOff + 2] = (byte)(num >>> 16);
-            out[outOff + 1] = (byte)(num >>> 8);
-            out[outOff] =     (byte)num;
-    }
-}
diff --git a/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
index f209b9f..728a2e7 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
@@ -84,7 +84,11 @@
 
                 reset();
 
-                cipher.init(true, ivParam.getParameters());
+                // if null it's an IV changed only.
+                if (ivParam.getParameters() != null)
+                {
+                    cipher.init(true, ivParam.getParameters());
+                }
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
index a92e5a5..af9f18d 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
@@ -57,7 +57,12 @@
           System.arraycopy(iv, 0, IV, 0, IV.length);
 
           reset();
-          cipher.init(true, ivParam.getParameters());
+
+          // if null it's an IV changed only.
+          if (ivParam.getParameters() != null)
+          {
+            cipher.init(true, ivParam.getParameters());
+          }
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
index e1949dc..ce02be4 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
@@ -73,9 +73,19 @@
 
     static void multiplyP8(int[] x)
     {
-        for (int i = 8; i != 0; --i)
+//        for (int i = 8; i != 0; --i)
+//        {
+//            multiplyP(x);
+//        }
+
+        int lsw = x[3];
+        shiftRightN(x, 8);
+        for (int i = 7; i >= 0; --i)
         {
-            multiplyP(x);
+            if ((lsw & (1 << i)) != 0)
+            {
+                x[0] ^= (0xe1000000 >>> (7 - i));
+            }
         }
     }
 
@@ -111,6 +121,22 @@
         }
     }
 
+    static void shiftRightN(int[] block, int n)
+    {
+        int i = 0;
+        int bits = 0;
+        for (;;)
+        {
+            int b = block[i];
+            block[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)
diff --git a/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
index 47728b1..9d21cf0 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
@@ -94,9 +94,6 @@
             z[3] ^= m[3];
         }
 
-        Pack.intToBigEndian(z[0], x, 0);
-        Pack.intToBigEndian(z[1], x, 4);
-        Pack.intToBigEndian(z[2], x, 8);
-        Pack.intToBigEndian(z[3], x, 12);
+        Pack.intToBigEndian(z, x, 0);
     }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/params/DHParameters.java b/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
index 95352ce..b679287 100644
--- a/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
+++ b/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
@@ -1,9 +1,9 @@
 package org.bouncycastle.crypto.params;
 
-import org.bouncycastle.crypto.CipherParameters;
-
 import java.math.BigInteger;
 
+import org.bouncycastle.crypto.CipherParameters;
+
 public class DHParameters
     implements CipherParameters
 {
@@ -84,9 +84,10 @@
     {
         if (l != 0)
         {
-            if (l >= p.bitLength())
+            BigInteger bigL = BigInteger.valueOf(2L ^ (l - 1));
+            if (bigL.compareTo(p) == 1)
             {
-                throw new IllegalArgumentException("when l value specified, it must be less than bitlength(p)");
+                throw new IllegalArgumentException("when l value specified, it must satisfy 2^(l-1) <= p");
             }
             if (l < m)
             {
diff --git a/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
index 99217b0..dac6efe 100644
--- a/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
+++ b/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -143,20 +143,19 @@
     }
 
     private BigInteger calculateE(BigInteger n, byte[] message)
-    {  
-        if (n.bitLength() > message.length * 8)
+    {
+        int log2n = n.bitLength();
+        int messageBitLength = message.length * 8;
+
+        if (log2n >= messageBitLength)
         {
             return new BigInteger(1, message);
         }
         else
         {
-            int messageBitLength = message.length * 8;
             BigInteger trunc = new BigInteger(1, message);
 
-            if (messageBitLength - n.bitLength() > 0)
-            {
-                trunc = trunc.shiftRight(messageBitLength - n.bitLength());
-            }
+            trunc = trunc.shiftRight(messageBitLength - log2n);
 
             return trunc;
         }
diff --git a/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
index 58d1b87..a975d27 100644
--- a/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
+++ b/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -1,7 +1,11 @@
 package org.bouncycastle.crypto.signers;
 
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
@@ -18,8 +22,7 @@
 import org.bouncycastle.crypto.engines.RSABlindedEngine;
 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithRandom;
-
-import java.util.Hashtable;
+import org.bouncycastle.util.Arrays;
 
 public class RSADigestSigner
     implements Signer
@@ -36,12 +39,16 @@
      */
     static
     {
-        oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
-        oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
-        oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+        // BEGIN android-removed
+        // oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+        // oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+        // oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+        // 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-384", NISTObjectIdentifiers.id_sha384);
         oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
@@ -58,7 +65,7 @@
     {
         this.digest = digest;
 
-        algId = new AlgorithmIdentifier((DERObjectIdentifier)oidMap.get(digest.getAlgorithmName()), DERNull.INSTANCE);
+        algId = new AlgorithmIdentifier((ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()), DERNull.INSTANCE);
     }
 
     /**
@@ -143,8 +150,15 @@
         byte[] hash = new byte[digest.getDigestSize()];
         digest.doFinal(hash, 0);
 
-        byte[] data = derEncode(hash);
-        return rsaEngine.processBlock(data, 0, data.length);
+        try
+        {
+            byte[] data = derEncode(hash);
+            return rsaEngine.processBlock(data, 0, data.length);
+        }
+        catch (IOException e)
+        {
+            throw new CryptoException("unable to encode signature: " + e.getMessage(), e);
+        }
     }
 
     /**
@@ -160,6 +174,7 @@
         }
 
         byte[] hash = new byte[digest.getDigestSize()];
+
         digest.doFinal(hash, 0);
 
         byte[] sig;
@@ -177,13 +192,7 @@
 
         if (sig.length == expected.length)
         {
-            for (int i = 0; i < sig.length; i++)
-            {
-                if (sig[i] != expected[i])
-                {
-                    return false;
-                }
-            }
+            return Arrays.constantTimeAreEqual(sig, expected);
         }
         else if (sig.length == expected.length - 2)  // NULL left out
         {
@@ -193,28 +202,24 @@
             expected[1] -= 2;      // adjust lengths
             expected[3] -= 2;
 
+            int nonEqual = 0;
+
             for (int i = 0; i < hash.length; i++)
             {
-                if (sig[sigOffset + i] != expected[expectedOffset + i])  // check hash
-                {
-                    return false;
-                }
+                nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
             }
 
             for (int i = 0; i < sigOffset; i++)
             {
-                if (sig[i] != expected[i])  // check header less NULL
-                {
-                    return false;
-                }
+                nonEqual |= (sig[i] ^ expected[i]);  // check header less NULL
             }
+
+            return nonEqual == 0;
         }
         else
         {
             return false;
         }
-
-        return true;
     }
 
     public void reset()
@@ -224,9 +229,10 @@
 
     private byte[] derEncode(
         byte[] hash)
+        throws IOException
     {
         DigestInfo dInfo = new DigestInfo(algId, hash);
 
-        return dInfo.getDEREncoded();
+        return dInfo.getEncoded(ASN1Encoding.DER);
     }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/util/Pack.java b/src/main/java/org/bouncycastle/crypto/util/Pack.java
index cdea3af..857b765 100644
--- a/src/main/java/org/bouncycastle/crypto/util/Pack.java
+++ b/src/main/java/org/bouncycastle/crypto/util/Pack.java
@@ -11,6 +11,15 @@
         return n;
     }
 
+    public static void bigEndianToInt(byte[] bs, int off, int[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = bigEndianToInt(bs, off);
+            off += 4;
+        }
+    }
+
     public static void intToBigEndian(int n, byte[] bs, int off)
     {
         bs[  off] = (byte)(n >>> 24);
@@ -19,6 +28,15 @@
         bs[++off] = (byte)(n       );
     }
 
+    public static void intToBigEndian(int[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            intToBigEndian(ns[i], bs, off);
+            off += 4;
+        }
+    }
+
     public static long bigEndianToLong(byte[] bs, int off)
     {
         int hi = bigEndianToInt(bs, off);
@@ -34,13 +52,22 @@
 
     public static int littleEndianToInt(byte[] bs, int off)
     {
-        int n = bs[  off];
+        int n = bs[  off] & 0xff;
         n |= (bs[++off] & 0xff) << 8;
         n |= (bs[++off] & 0xff) << 16;
-        n |= (bs[++off] & 0xff) << 24;
+        n |= bs[++off] << 24;
         return n;
     }
 
+    public static void littleEndianToInt(byte[] bs, int off, int[] ns)
+	{
+		for (int i = 0; i < ns.length; ++i)
+		{
+			ns[i] = littleEndianToInt(bs, off);
+			off += 4;
+		}
+	}
+
     public static void intToLittleEndian(int n, byte[] bs, int off)
     {
         bs[  off] = (byte)(n       );
@@ -49,6 +76,15 @@
         bs[++off] = (byte)(n >>> 24);
     }
 
+	public static void intToLittleEndian(int[] ns, byte[] bs, int off)
+	{
+		for (int i = 0; i < ns.length; ++i)
+		{
+			intToLittleEndian(ns[i], bs, off);
+			off += 4;
+		}
+	}
+
     public static long littleEndianToLong(byte[] bs, int off)
     {
         int lo = littleEndianToInt(bs, off);
diff --git a/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index a352884..8ddfac8 100644
--- a/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -4,13 +4,12 @@
 import java.io.InputStream;
 import java.math.BigInteger;
 
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // BEGIN android-removed
 // import org.bouncycastle.asn1.oiw.ElGamalParameter;
@@ -19,8 +18,8 @@
 import org.bouncycastle.asn1.pkcs.DHParameter;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
-import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+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;
@@ -58,7 +57,7 @@
      */
     public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException
     {
-        return createKey(PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(privateKeyInfoData)));
+        return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData)));
     }
 
     /**
@@ -83,12 +82,11 @@
      */
     public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException
     {
-        AlgorithmIdentifier algId = keyInfo.getAlgorithmId();
+        AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
 
         if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
         {
-            RSAPrivateKeyStructure keyStructure = new RSAPrivateKeyStructure(
-                (ASN1Sequence)keyInfo.getPrivateKey());
+            RSAPrivateKey keyStructure = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
 
             return new RSAPrivateCrtKeyParameters(keyStructure.getModulus(),
                 keyStructure.getPublicExponent(), keyStructure.getPrivateExponent(),
@@ -97,11 +95,10 @@
         }
         // TODO?
 //      else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
-        else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
         {
-            DHParameter params = new DHParameter(
-                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
+            DHParameter params = DHParameter.getInstance(algId.getParameters());
+            DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
 
             BigInteger lVal = params.getL();
             int l = lVal == null ? 0 : lVal.intValue();
@@ -110,72 +107,70 @@
             return new DHPrivateKeyParameters(derX.getValue(), dhParams);
         }
         // BEGIN android-removed
-        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
         // {
-        //     ElGamalParameter params = new ElGamalParameter(
-        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-        //     DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
+        //     ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+        //     DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
         //
         //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
         //         params.getP(), params.getG()));
         // }
         // END android-removed
-        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
+        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa))
         {
-            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
-            DEREncodable de = keyInfo.getAlgorithmId().getParameters();
+            DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
+            ASN1Encodable de = algId.getParameters();
 
             DSAParameters parameters = null;
             if (de != null)
             {
-                DSAParameter params = DSAParameter.getInstance(de.getDERObject());
+                DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
                 parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
             }
 
             return new DSAPrivateKeyParameters(derX.getValue(), parameters);
         }
-        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
         {
-            X962Parameters params = new X962Parameters(
-                (DERObject)keyInfo.getAlgorithmId().getParameters());
-            ECDomainParameters dParams = null;
+            X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters());
 
+            X9ECParameters x9;
             if (params.isNamedCurve())
             {
-                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-                X9ECParameters ecP = X962NamedCurves.getByOID(oid);
+                ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+                x9 = X962NamedCurves.getByOID(oid);
 
-                if (ecP == null)
+                if (x9 == null)
                 {
-                    ecP = SECNamedCurves.getByOID(oid);
+                    x9 = SECNamedCurves.getByOID(oid);
 
-                    if (ecP == null)
+                    if (x9 == null)
                     {
-                        ecP = NISTNamedCurves.getByOID(oid);
+                        x9 = NISTNamedCurves.getByOID(oid);
 
                         // BEGIN android-removed
-                        // if (ecP == null)
+                        // if (x9 == null)
                         // {
-                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
+                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
                         // }
                         // END android-removed
                     }
                 }
-
-                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
-                    ecP.getH(), ecP.getSeed());
             }
             else
             {
-                X9ECParameters ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
-                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
-                    ecP.getH(), ecP.getSeed());
+                x9 = X9ECParameters.getInstance(params.getParameters());
             }
 
-            ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
-                (ASN1Sequence)keyInfo.getPrivateKey());
+            ECPrivateKey ec = ECPrivateKey.getInstance(keyInfo.parsePrivateKey());
+            BigInteger d = ec.getKey();
 
-            return new ECPrivateKeyParameters(ec.getKey(), dParams);
+            // TODO We lose any named parameters here
+
+            ECDomainParameters dParams = new ECDomainParameters(
+                    x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+
+            return new ECPrivateKeyParameters(d, dParams);
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index 5e93a36..05520f0 100644
--- a/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -4,15 +4,13 @@
 import java.io.InputStream;
 import java.math.BigInteger;
 
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // BEGIN android-removed
@@ -21,13 +19,13 @@
 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;
 // 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.RSAPublicKeyStructure;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
 import org.bouncycastle.asn1.x9.DHDomainParameters;
@@ -67,7 +65,7 @@
      */
     public static AsymmetricKeyParameter createKey(byte[] keyInfoData) throws IOException
     {
-        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(keyInfoData)));
+        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
     }
 
     /**
@@ -91,23 +89,22 @@
      */
     public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException
     {
-        AlgorithmIdentifier algId = keyInfo.getAlgorithmId();
+        AlgorithmIdentifier algId = keyInfo.getAlgorithm();
 
-        if (algId.getObjectId().equals(PKCSObjectIdentifiers.rsaEncryption)
-            || algId.getObjectId().equals(X509ObjectIdentifiers.id_ea_rsa))
+        if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)
+            || algId.getAlgorithm().equals(X509ObjectIdentifiers.id_ea_rsa))
         {
-            RSAPublicKeyStructure pubKey = new RSAPublicKeyStructure(
-                (ASN1Sequence)keyInfo.getPublicKey());
+            RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey());
 
             return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
         }
-        else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
+        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.dhpublicnumber))
         {
-            DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.getPublicKey());
+            DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey());
 
             BigInteger y = dhPublicKey.getY().getValue();
 
-            DHDomainParameters dhParams = DHDomainParameters.getInstance(keyInfo.getAlgorithmId().getParameters());
+            DHDomainParameters dhParams = DHDomainParameters.getInstance(algId.getParameters());
 
             BigInteger p = dhParams.getP().getValue();
             BigInteger g = dhParams.getG().getValue();
@@ -133,11 +130,10 @@
 
             return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
         }
-        else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
         {
-            DHParameter params = new DHParameter(
-                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-            DERInteger derY = (DERInteger)keyInfo.getPublicKey();
+            DHParameter params = DHParameter.getInstance(algId.getParameters());
+            DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
 
             BigInteger lVal = params.getL();
             int l = lVal == null ? 0 : lVal.intValue();
@@ -146,74 +142,70 @@
             return new DHPublicKeyParameters(derY.getValue(), dhParams);
         }
         // BEGIN android-removed
-        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
         // {
-        //     ElGamalParameter params = new ElGamalParameter(
-        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-        //     DERInteger derY = (DERInteger)keyInfo.getPublicKey();
+        //     ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+        //     DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
         //
         //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
         //         params.getP(), params.getG()));
         // }
         // END android-removed
-        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa)
-            || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
+        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
+            || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1))
         {
-            DERInteger derY = (DERInteger)keyInfo.getPublicKey();
-            DEREncodable de = keyInfo.getAlgorithmId().getParameters();
+            DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
+            ASN1Encodable de = algId.getParameters();
 
             DSAParameters parameters = null;
             if (de != null)
             {
-                DSAParameter params = DSAParameter.getInstance(de.getDERObject());
+                DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
                 parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
             }
 
             return new DSAPublicKeyParameters(derY.getValue(), parameters);
         }
-        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
         {
             X962Parameters params = new X962Parameters(
-                (DERObject)keyInfo.getAlgorithmId().getParameters());
-            ECDomainParameters dParams = null;
+                (ASN1Primitive)algId.getParameters());
 
+            X9ECParameters x9;
             if (params.isNamedCurve())
             {
-                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-                X9ECParameters ecP = X962NamedCurves.getByOID(oid);
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+                x9 = X962NamedCurves.getByOID(oid);
 
-                if (ecP == null)
+                if (x9 == null)
                 {
-                    ecP = SECNamedCurves.getByOID(oid);
+                    x9 = SECNamedCurves.getByOID(oid);
 
-                    if (ecP == null)
+                    if (x9 == null)
                     {
-                        ecP = NISTNamedCurves.getByOID(oid);
+                        x9 = NISTNamedCurves.getByOID(oid);
 
                         // BEGIN android-removed
-                        // if (ecP == null)
+                        // if (x9 == null)
                         // {
-                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
+                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
                         // }
                         // END android-removed
                     }
                 }
-
-                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
-                    ecP.getH(), ecP.getSeed());
             }
             else
             {
-                X9ECParameters ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
-                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
-                    ecP.getH(), ecP.getSeed());
+                x9 = X9ECParameters.getInstance(params.getParameters());
             }
 
-            DERBitString bits = keyInfo.getPublicKeyData();
-            byte[] data = bits.getBytes();
-            ASN1OctetString key = new DEROctetString(data);
+            ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes());
+            X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key);
 
-            X9ECPoint derQ = new X9ECPoint(dParams.getCurve(), key);
+            // TODO We lose any named parameters here
+            
+            ECDomainParameters dParams = new ECDomainParameters(
+                    x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
 
             return new ECPublicKeyParameters(derQ.getPoint(), dParams);
         }
diff --git a/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java b/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java
new file mode 100644
index 0000000..807bdfd
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java
@@ -0,0 +1,88 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public class DefaultJcaJceHelper
+    implements JcaJceHelper
+{
+    public Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        return Cipher.getInstance(algorithm);
+    }
+
+    public Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Mac.getInstance(algorithm);
+    }
+
+    public KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyAgreement.getInstance(algorithm);
+    }
+
+    public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameterGenerator.getInstance(algorithm);
+    }
+
+    public AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameters.getInstance(algorithm);
+    }
+
+    public KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyGenerator.getInstance(algorithm);
+    }
+
+    public KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyFactory.getInstance(algorithm);
+    }
+
+    public KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyPairGenerator.getInstance(algorithm);
+    }
+
+    public MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return MessageDigest.getInstance(algorithm);
+    }
+
+    public Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Signature.getInstance(algorithm);
+    }
+
+    public CertificateFactory createCertificateFactory(String algorithm)
+        throws NoSuchAlgorithmException, CertificateException
+    {
+        return CertificateFactory.getInstance(algorithm);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java b/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java
new file mode 100644
index 0000000..d8a4900
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java
@@ -0,0 +1,55 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public interface JcaJceHelper
+{
+    Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+
+    Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    CertificateFactory createCertificateFactory(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException;
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java b/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java
new file mode 100644
index 0000000..9abf52d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public class NamedJcaJceHelper
+    implements JcaJceHelper
+{
+    protected final String providerName;
+
+    public NamedJcaJceHelper(String providerName)
+    {
+        this.providerName = providerName;
+    }
+
+    public Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException
+    {
+        return Cipher.getInstance(algorithm, providerName);
+    }
+
+    public Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return Mac.getInstance(algorithm, providerName);
+    }
+
+    public KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyAgreement.getInstance(algorithm, providerName);
+    }
+
+    public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return AlgorithmParameterGenerator.getInstance(algorithm, providerName);
+    }
+
+    public AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return AlgorithmParameters.getInstance(algorithm, providerName);
+    }
+
+    public KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyGenerator.getInstance(algorithm, providerName);
+    }
+
+    public KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyFactory.getInstance(algorithm, providerName);
+    }
+
+    public KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyPairGenerator.getInstance(algorithm, providerName);
+    }
+
+    public MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return MessageDigest.getInstance(algorithm, providerName);
+    }
+
+    public Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return Signature.getInstance(algorithm, providerName);
+    }
+
+    public CertificateFactory createCertificateFactory(String algorithm)
+        throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException
+    {
+        return CertificateFactory.getInstance(algorithm, providerName);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java b/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java
new file mode 100644
index 0000000..83ff765
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public class ProviderJcaJceHelper
+    implements JcaJceHelper
+{
+    protected final Provider provider;
+
+    public ProviderJcaJceHelper(Provider provider)
+    {
+        this.provider = provider;
+    }
+
+    public Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        return Cipher.getInstance(algorithm, provider);
+    }
+
+    public Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Mac.getInstance(algorithm, provider);
+    }
+
+    public KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyAgreement.getInstance(algorithm, provider);
+    }
+
+    public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameterGenerator.getInstance(algorithm, provider);
+    }
+
+    public AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameters.getInstance(algorithm, provider);
+    }
+
+    public KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyGenerator.getInstance(algorithm, provider);
+    }
+
+    public KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyFactory.getInstance(algorithm, provider);
+    }
+
+    public KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyPairGenerator.getInstance(algorithm, provider);
+    }
+
+    public MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return MessageDigest.getInstance(algorithm, provider);
+    }
+
+    public Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Signature.getInstance(algorithm, provider);
+    }
+
+    public CertificateFactory createCertificateFactory(String algorithm)
+        throws NoSuchAlgorithmException, CertificateException
+    {
+        return CertificateFactory.getInstance(algorithm, provider);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java b/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java
new file mode 100644
index 0000000..235bfe5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java
@@ -0,0 +1,38 @@
+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/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
new file mode 100644
index 0000000..8055576
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class DH
+{
+    private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".dh.";
+
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("KeyPairGenerator.DH", PREFIX + "KeyPairGeneratorSpi");
+            provider.addAlgorithm("Alg.Alias.KeyPairGenerator.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("KeyAgreement.DH", PREFIX + "KeyAgreementSpi");
+            provider.addAlgorithm("Alg.Alias.KeyAgreement.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("KeyFactory.DH", PREFIX + "KeyFactorySpi");
+            provider.addAlgorithm("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("AlgorithmParameters.DH", PREFIX + "AlgorithmParametersSpi");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
new file mode 100644
index 0000000..830334b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.dsa.DSAUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class DSA
+{
+    private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".dsa.";
+
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+        
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("AlgorithmParameters.DSA", PREFIX + "AlgorithmParametersSpi");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.DSA", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+            provider.addAlgorithm("KeyPairGenerator.DSA", PREFIX + "KeyPairGeneratorSpi");
+            provider.addAlgorithm("KeyFactory.DSA", PREFIX + "KeyFactorySpi");
+
+            // BEGIN android-changed
+            provider.addAlgorithm("Signature.SHA1withDSA", PREFIX + "DSASigner$stdDSA");
+            // END android-changed
+            provider.addAlgorithm("Signature.NONEWITHDSA", PREFIX + "DSASigner$noneDSA");
+
+            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);
+            // 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
+
+            // BEGIN android-added
+            provider.addAlgorithm("Alg.Alias.Signature.DSA", "SHA1withDSA");
+            // 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.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
+            // END android-changed
+
+            AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+            for (int i = 0; i != DSAUtil.dsaOids.length; i++)
+            {
+                registerOid(provider, DSAUtil.dsaOids[i], "DSA", keyFact);
+                registerOidAlgorithmParameters(provider, DSAUtil.dsaOids[i], "DSA");
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
new file mode 100644
index 0000000..bacb6d6
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -0,0 +1,99 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+// BEGIN android-removed
+// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class EC
+{
+    private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".ec.";
+
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("KeyAgreement.ECDH", PREFIX + "KeyAgreementSpi$DH");
+            // BEGIN android-removed
+            // provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC");
+            // provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV");
+            // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDF");
+            // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF");
+            // END android-removed
+
+            registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC());
+            // TODO Should this be an alias for ECDH?
+            registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+            // BEGIN android-removed
+            // registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+            // END android-removed
+
+            // BEGIN android-removed
+            // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC");
+            // // TODO Should this be an alias for ECDH?
+            // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+            // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC");
+            // END android-removed
+
+            provider.addAlgorithm("KeyFactory.EC", PREFIX + "KeyFactorySpi$EC");
+            // BEGIN android-removed
+            // provider.addAlgorithm("KeyFactory.ECDSA", PREFIX + "KeyFactorySpi$ECDSA");
+            // provider.addAlgorithm("KeyFactory.ECDH", PREFIX + "KeyFactorySpi$ECDH");
+            // provider.addAlgorithm("KeyFactory.ECDHC", PREFIX + "KeyFactorySpi$ECDHC");
+            // provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV");
+            // END android-removed
+
+            provider.addAlgorithm("KeyPairGenerator.EC", PREFIX + "KeyPairGeneratorSpi$EC");
+            // BEGIN android-removed
+            // provider.addAlgorithm("KeyPairGenerator.ECDSA", PREFIX + "KeyPairGeneratorSpi$ECDSA");
+            // provider.addAlgorithm("KeyPairGenerator.ECDH", PREFIX + "KeyPairGeneratorSpi$ECDH");
+            // provider.addAlgorithm("KeyPairGenerator.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC");
+            // provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
+            // provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV");
+            // END android-removed
+
+            provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA");
+            provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone");
+
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
+            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");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+            // END android-removed
+
+            // BEGIN android-removed
+            // addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+            // END android-removed
+            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);
+            // BEGIN android-removed
+            // addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+            //
+            // provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
+            // provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224");
+            // provider.addAlgorithm("Signature.SHA256WITHECNR", PREFIX + "SignatureSpi$ecNR256");
+            // provider.addAlgorithm("Signature.SHA384WITHECNR", PREFIX + "SignatureSpi$ecNR384");
+            // provider.addAlgorithm("Signature.SHA512WITHECNR", PREFIX + "SignatureSpi$ecNR512");
+            //
+            // addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+            // addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+            // addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+            // END android-removed
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
new file mode 100644
index 0000000..dcf52c8
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
@@ -0,0 +1,217 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class RSA
+{
+    private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".rsa.";
+
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("AlgorithmParameters.OAEP", PREFIX + "AlgorithmParametersSpi$OAEP");
+            // BEGIN android-removed
+            // provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS");
+            //
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
+            //
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
+            //
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAANDMGF1", "PSS");
+            // END android-removed
+
+            provider.addAlgorithm("Cipher.RSA", PREFIX + "CipherSpi$NoPadding");
+            // BEGIN android-changed
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA/RAW", "RSA");
+            // END android-changed
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher.RSA/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+            // provider.addAlgorithm("Cipher.1.2.840.113549.1.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+            // provider.addAlgorithm("Cipher.2.5.8.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+            // provider.addAlgorithm("Cipher.RSA/1", PREFIX + "CipherSpi$PKCS1v1_5Padding_PrivateOnly");
+            // provider.addAlgorithm("Cipher.RSA/2", PREFIX + "CipherSpi$PKCS1v1_5Padding_PublicOnly");
+            // provider.addAlgorithm("Cipher.RSA/OAEP", PREFIX + "CipherSpi$OAEPPadding");
+            // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding");
+            // provider.addAlgorithm("Cipher.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding");
+            // END android-removed
+
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//RAW", "RSA");
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
+            // provider.addAlgorithm("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
+            // provider.addAlgorithm("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
+            // END android-removed
+
+            provider.addAlgorithm("KeyFactory.RSA", PREFIX + "KeyFactorySpi");
+            provider.addAlgorithm("KeyPairGenerator.RSA", PREFIX + "KeyPairGeneratorSpi");
+
+            AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+            registerOid(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA", keyFact);
+            registerOid(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA", keyFact);
+            registerOid(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA", keyFact);
+            // BEGIN android-removed
+            // registerOid(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "RSA", keyFact);
+            //
+            // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA");
+            // registerOidAlgorithmParameters(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA");
+            // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
+            // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
+            //
+            //
+            // provider.addAlgorithm("Signature.RSASSA-PSS", PREFIX + "PSSSignatureSpi$PSSwithRSA");
+            // provider.addAlgorithm("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+            // provider.addAlgorithm("Signature.OID." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+            //
+            // provider.addAlgorithm("Signature.SHA224withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA224withRSA");
+            // provider.addAlgorithm("Signature.SHA256withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA256withRSA");
+            // provider.addAlgorithm("Signature.SHA384withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA384withRSA");
+            // provider.addAlgorithm("Signature.SHA512withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA512withRSA");
+            //
+            // provider.addAlgorithm("Signature.RSA", PREFIX + "DigestSignatureSpi$noneRSA");
+            // provider.addAlgorithm("Signature.RAWRSASSA-PSS", PREFIX + "PSSSignatureSpi$nonePSS");
+            //
+            // provider.addAlgorithm("Alg.Alias.Signature.RAWRSA", "RSA");
+            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSA", "RSA");
+            // provider.addAlgorithm("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAANDMGF1", "RAWRSASSA-PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
+            //
+            //
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHRSAANDMGF1", "SHA224withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHRSAANDMGF1", "SHA256withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHRSAANDMGF1", "SHA384withRSA/PSS");
+            // provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHRSAANDMGF1", "SHA512withRSA/PSS");
+            //
+            // if (provider.hasAlgorithm("MessageDigest", "MD2"))
+            // {
+            //     addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
+            // }
+            //
+            // if (provider.hasAlgorithm("MessageDigest", "MD2"))
+            // {
+            //     addDigestSignature(provider, "MD4", PREFIX + "DigestSignatureSpi$MD4", PKCSObjectIdentifiers.md4WithRSAEncryption);
+            // }
+            //
+            // if (provider.hasAlgorithm("MessageDigest", "MD2"))
+            // {
+            //     addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption);
+            //     provider.addAlgorithm("Signature.MD5withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption");
+            //     provider.addAlgorithm("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
+            // }
+            // END android-removed
+
+            if (provider.hasAlgorithm("MessageDigest", "SHA1"))
+            {
+                // BEGIN android-removed
+                // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
+                // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
+                // provider.addAlgorithm("Signature.SHA1withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA1withRSA");
+                // provider.addAlgorithm("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
+                // provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHRSAANDMGF1", "SHA1withRSA/PSS");
+                // END android-removed
+
+                addDigestSignature(provider, "SHA1", PREFIX + "DigestSignatureSpi$SHA1", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+
+                // BEGIN android-removed
+                // provider.addAlgorithm("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
+                // provider.addAlgorithm("Signature.SHA1withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption");
+                // END android-removed
+                provider.addAlgorithm("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+                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, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+            addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+            addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+
+            // BEGIN android-removed
+            // if (provider.hasAlgorithm("MessageDigest", "RIPEMD128"))
+            // {
+            //     addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+            //     addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null);
+            // }
+            //
+            // if (provider.hasAlgorithm("MessageDigest", "RIPEMD160"))
+            // {
+            //     addDigestSignature(provider, "RIPEMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+            //     addDigestSignature(provider, "RMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", null);
+            //     provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
+            //     provider.addAlgorithm("Signature.RIPEMD160withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$RIPEMD160WithRSAEncryption");
+            // }
+            //
+            // if (provider.hasAlgorithm("MessageDigest", "RIPEMD256"))
+            // {
+            //     addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+            //     addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null);
+            // }
+            // END android-removed
+        }
+
+        private void addDigestSignature(
+            ConfigurableProvider provider,
+            String digest,
+            String className,
+            ASN1ObjectIdentifier oid)
+        {
+            String mainName = digest + "WITHRSA";
+            String jdk11Variation1 = digest + "withRSA";
+            String jdk11Variation2 = digest + "WithRSA";
+            String alias = digest + "/" + "RSA";
+            String longName = digest + "WITHRSAENCRYPTION";
+            String longJdk11Variation1 = digest + "withRSAEncryption";
+            String longJdk11Variation2 = digest + "WithRSAEncryption";
+
+            provider.addAlgorithm("Signature." + mainName, className);
+            provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + longName, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation1, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation2, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+
+            if (oid != null)
+            {
+                provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+                provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java
new file mode 100644
index 0000000..a9fb6b2
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java
@@ -0,0 +1,33 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * For some reason the class path project thinks that such a KeyFactory will exist.
+ */
+public class X509
+{
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN android-removed
+            // provider.addAlgorithm("KeyFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory");
+            // provider.addAlgorithm("Alg.Alias.KeyFactory.X509", "X.509");
+            // END android-removed
+
+            //
+            // certificate factories.
+            //
+            provider.addAlgorithm("CertificateFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory");
+            provider.addAlgorithm("Alg.Alias.CertificateFactory.X509", "X.509");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..8bdcc55
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.crypto.generators.DHParametersGenerator;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class AlgorithmParameterGeneratorSpi
+    extends java.security.AlgorithmParameterGeneratorSpi
+{
+    protected SecureRandom random;
+    protected int strength = 1024;
+
+    private int l = 0;
+
+    protected void engineInit(
+        int strength,
+        SecureRandom random)
+    {
+        this.strength = strength;
+        this.random = random;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec genParamSpec,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(genParamSpec instanceof DHGenParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+        }
+        DHGenParameterSpec spec = (DHGenParameterSpec)genParamSpec;
+
+        this.strength = spec.getPrimeSize();
+        this.l = spec.getExponentSize();
+        this.random = random;
+    }
+
+    protected AlgorithmParameters engineGenerateParameters()
+    {
+        DHParametersGenerator pGen = new DHParametersGenerator();
+
+        if (random != null)
+        {
+            pGen.init(strength, 20, random);
+        }
+        else
+        {
+            pGen.init(strength, 20, new SecureRandom());
+        }
+
+        DHParameters p = pGen.generateParameters();
+
+        AlgorithmParameters params;
+
+        try
+        {
+            params = AlgorithmParameters.getInstance("DH", BouncyCastleProvider.PROVIDER_NAME);
+            params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.getMessage());
+        }
+
+        return params;
+    }
+
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..c771123
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+
+public class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    DHParameterSpec     currentSpec;
+
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+
+
+
+        /**
+         * Return the PKCS#3 ASN.1 structure DHParameter.
+         * <p>
+         * <pre>
+         *  DHParameter ::= SEQUENCE {
+         *                   prime INTEGER, -- p
+         *                   base INTEGER, -- g
+         *                   privateValueLength INTEGER OPTIONAL}
+         * </pre>
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            DHParameter dhP = new DHParameter(currentSpec.getP(), currentSpec.getG(), currentSpec.getL());
+
+            try
+            {
+                return dhP.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding DHParameters");
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == DHParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to DH parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof DHParameterSpec))
+            {
+                throw new InvalidParameterSpecException("DHParameterSpec required to initialise a Diffie-Hellman algorithm parameters object");
+            }
+
+            this.currentSpec = (DHParameterSpec)paramSpec;
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            try
+            {
+                DHParameter dhP = DHParameter.getInstance(params);
+
+                if (dhP.getL() != null)
+                {
+                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG(), dhP.getL().intValue());
+                }
+                else
+                {
+                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG());
+                }
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid DH Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid DH Parameter encoding.");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (isASN1FormatString(format))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+
+        protected String engineToString() 
+        {
+            return "Diffie-Hellman Parameters";
+        }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
new file mode 100644
index 0000000..332e2eb
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
@@ -0,0 +1,214 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+
+public class BCDHPrivateKey
+    implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+    static final long serialVersionUID = 311058815616901812L;
+    
+    private BigInteger      x;
+
+    private transient DHParameterSpec dhSpec;
+    private transient PrivateKeyInfo  info;
+
+    private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCDHPrivateKey()
+    {
+    }
+
+    BCDHPrivateKey(
+        DHPrivateKey key)
+    {
+        this.x = key.getX();
+        this.dhSpec = key.getParams();
+    }
+
+    BCDHPrivateKey(
+        DHPrivateKeySpec spec)
+    {
+        this.x = spec.getX();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    public BCDHPrivateKey(
+        PrivateKeyInfo info)
+        throws IOException
+    {
+        ASN1Sequence    seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+        ASN1Integer      derX = (ASN1Integer)info.parsePrivateKey();
+        ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+        this.info = info;
+        this.x = derX.getValue();
+
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            DHParameter params = DHParameter.getInstance(seq);
+
+            if (params.getL() != null)
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            }
+            else
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            }
+        }
+        else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+            this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
+        }
+    }
+
+    BCDHPrivateKey(
+        DHPrivateKeyParameters params)
+    {
+        this.x = params.getX();
+        this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+            if (info != null)
+            {
+                return info.getEncoded(ASN1Encoding.DER);
+            }
+
+            PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(getX()));
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DHPrivateKey))
+        {
+            return false;
+        }
+
+        DHPrivateKey other = (DHPrivateKey)o;
+
+        return this.getX().equals(other.getX())
+            && this.getParams().getG().equals(other.getParams().getG())
+            && this.getParams().getP().equals(other.getParams().getP())
+            && this.getParams().getL() == other.getParams().getL();
+    }
+
+    public int hashCode()
+    {
+        return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+        this.info = null;
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
new file mode 100644
index 0000000..0697f75
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
@@ -0,0 +1,204 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCDHPublicKey
+    implements DHPublicKey
+{
+    static final long serialVersionUID = -216691575254424324L;
+    
+    private BigInteger              y;
+
+    private transient DHParameterSpec         dhSpec;
+    private transient SubjectPublicKeyInfo    info;
+    
+    BCDHPublicKey(
+        DHPublicKeySpec spec)
+    {
+        this.y = spec.getY();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    BCDHPublicKey(
+        DHPublicKey key)
+    {
+        this.y = key.getY();
+        this.dhSpec = key.getParams();
+    }
+
+    BCDHPublicKey(
+        DHPublicKeyParameters params)
+    {
+        this.y = params.getY();
+        this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+    }
+
+    BCDHPublicKey(
+        BigInteger y,
+        DHParameterSpec dhSpec)
+    {
+        this.y = y;
+        this.dhSpec = dhSpec;
+    }
+
+    public BCDHPublicKey(
+        SubjectPublicKeyInfo info)
+    {
+        this.info = info;
+
+        ASN1Integer              derY;
+        try
+        {
+            derY = (ASN1Integer)info.parsePublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DH public key");
+        }
+
+        this.y = derY.getValue();
+
+        ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithm().getParameters());
+        ASN1ObjectIdentifier id = info.getAlgorithm().getAlgorithm();
+
+        // we need the PKCS check to handle older keys marked with the X9 oid.
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
+        {
+            DHParameter             params = DHParameter.getInstance(seq);
+
+            if (params.getL() != null)
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            }
+            else
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            }
+        }
+        else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+            this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        if (info != null)
+        {
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+        }
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y));
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    private boolean isPKCSParam(ASN1Sequence seq)
+    {
+        if (seq.size() == 2)
+        {
+            return true;
+        }
+        
+        if (seq.size() > 3)
+        {
+            return false;
+        }
+
+        ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2));
+        ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0));
+
+        if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public int hashCode()
+    {
+        return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DHPublicKey))
+        {
+            return false;
+        }
+
+        DHPublicKey other = (DHPublicKey)o;
+
+        return this.getY().equals(other.getY())
+            && this.getParams().getG().equals(other.getParams().getG())
+            && this.getParams().getP().equals(other.getParams().getP())
+            && this.getParams().getL() == other.getParams().getL();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+        this.info = null;
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java
new file mode 100644
index 0000000..4bd7805
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class DHUtil
+{
+    static public AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPublicKey)
+        {
+            DHPublicKey    k = (DHPublicKey)key;
+
+            return new DHPublicKeyParameters(k.getY(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+
+        throw new InvalidKeyException("can't identify DH public key.");
+    }
+
+    static public AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPrivateKey)
+        {
+            DHPrivateKey    k = (DHPrivateKey)key;
+
+            return new DHPrivateKeyParameters(k.getX(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+                        
+        throw new InvalidKeyException("can't identify DH private key.");
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
similarity index 95%
rename from src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
index ef8f76a..5a66ffb 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
 
 import java.math.BigInteger;
 import java.security.InvalidAlgorithmParameterException;
@@ -8,7 +8,6 @@
 import java.security.spec.AlgorithmParameterSpec;
 import java.util.Hashtable;
 
-import javax.crypto.KeyAgreementSpi;
 import javax.crypto.SecretKey;
 import javax.crypto.ShortBufferException;
 import javax.crypto.interfaces.DHPrivateKey;
@@ -24,8 +23,8 @@
  * if you are using long term public keys, see the light-weight version for
  * details.
  */
-public class JCEDHKeyAgreement
-    extends KeyAgreementSpi
+public class KeyAgreementSpi
+    extends javax.crypto.KeyAgreementSpi
 {
     private BigInteger      x;
     private BigInteger      p;
@@ -96,7 +95,7 @@
             result = ((DHPublicKey)key).getY().modPow(x, p);
         }
 
-        return new JCEDHPublicKey(result, pubKey.getParams());
+        return new BCDHPublicKey(result, pubKey.getParams());
     }
 
     protected byte[] engineGenerateSecret() 
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
new file mode 100644
index 0000000..9565bd2
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
@@ -0,0 +1,128 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+{
+    public KeyFactorySpi()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
+        {
+            DHPrivateKey k = (DHPrivateKey)key;
+
+            return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
+        }
+        else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
+        {
+            DHPublicKey k = (DHPublicKey)key;
+
+            return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+        }
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPublicKey)
+        {
+            return new BCDHPublicKey((DHPublicKey)key);
+        }
+        else if (key instanceof DHPrivateKey)
+        {
+            return new BCDHPrivateKey((DHPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DHPrivateKeySpec)
+        {
+            return new BCDHPrivateKey((DHPrivateKeySpec)keySpec);
+        }
+
+        return super.engineGeneratePrivate(keySpec);
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DHPublicKeySpec)
+        {
+            return new BCDHPublicKey((DHPublicKeySpec)keySpec);
+        }
+
+        return super.engineGeneratePublic(keySpec);
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            return new BCDHPrivateKey(keyInfo);
+        }
+        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            return new BCDHPrivateKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            return new BCDHPublicKey(keyInfo);
+        }
+        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            return new BCDHPublicKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..69d5703
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator;
+import org.bouncycastle.crypto.generators.DHParametersGenerator;
+import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    private static Hashtable params = new Hashtable();
+
+    DHKeyGenerationParameters param;
+    DHBasicKeyPairGenerator engine = new DHBasicKeyPairGenerator();
+    int strength = 1024;
+    int certainty = 20;
+    SecureRandom random = new SecureRandom();
+    boolean initialised = false;
+
+    public KeyPairGeneratorSpi()
+    {
+        super("DH");
+    }
+
+    public void initialize(
+        int strength,
+        SecureRandom random)
+    {
+        this.strength = strength;
+        this.random = random;
+    }
+
+    public void initialize(
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof DHParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec");
+        }
+        DHParameterSpec dhParams = (DHParameterSpec)params;
+
+        param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+
+        engine.init(param);
+        initialised = true;
+    }
+
+    public KeyPair generateKeyPair()
+    {
+        if (!initialised)
+        {
+            // BEGIN android-changed
+            Integer paramStrength = Integer.valueOf(strength);
+            // END android-changed
+
+            if (params.containsKey(paramStrength))
+            {
+                param = (DHKeyGenerationParameters)params.get(paramStrength);
+            }
+            else
+            {
+                DHParameterSpec dhParams = BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters();
+
+                if (dhParams != null && dhParams.getP().bitLength() == strength)
+                {
+                    param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+                }
+                else
+                {
+                    DHParametersGenerator pGen = new DHParametersGenerator();
+
+                    pGen.init(strength, certainty, random);
+
+                    param = new DHKeyGenerationParameters(random, pGen.generateParameters());
+
+                    params.put(paramStrength, param);
+                }
+            }
+
+            engine.init(param);
+
+            initialised = true;
+        }
+
+        AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+        DHPublicKeyParameters pub = (DHPublicKeyParameters)pair.getPublic();
+        DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate();
+
+        return new KeyPair(new BCDHPublicKey(pub),
+            new BCDHPrivateKey(priv));
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..2e5ee56
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+//import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
+//import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public class AlgorithmParameterGeneratorSpi
+    extends java.security.AlgorithmParameterGeneratorSpi
+{
+    protected SecureRandom random;
+    protected int strength = 1024;
+
+    protected void engineInit(
+        int strength,
+        SecureRandom random)
+    {
+        if (strength < 512 || strength > 1024 || strength % 64 != 0)
+        {
+            throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
+        }
+
+        this.strength = strength;
+        this.random = random;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec genParamSpec,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DSA parameter generation.");
+    }
+
+    protected AlgorithmParameters engineGenerateParameters()
+    {
+        DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+        if (random != null)
+        {
+            pGen.init(strength, 20, random);
+        }
+        else
+        {
+            pGen.init(strength, 20, new SecureRandom());
+        }
+
+        DSAParameters p = pGen.generateParameters();
+
+        AlgorithmParameters params;
+
+        try
+        {
+            params = AlgorithmParameters.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+            params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.getMessage());
+        }
+
+        return params;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..6dfb8fb
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
@@ -0,0 +1,133 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.DSAParameter;
+
+public class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    DSAParameterSpec currentSpec;
+
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+    /**
+     * Return the X.509 ASN.1 structure DSAParameter.
+     * <p/>
+     * <pre>
+     *  DSAParameter ::= SEQUENCE {
+     *                   prime INTEGER, -- p
+     *                   subprime INTEGER, -- q
+     *                   base INTEGER, -- g}
+     * </pre>
+     */
+    protected byte[] engineGetEncoded()
+    {
+        DSAParameter dsaP = new DSAParameter(currentSpec.getP(), currentSpec.getQ(), currentSpec.getG());
+
+        try
+        {
+            return dsaP.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("Error encoding DSAParameters");
+        }
+    }
+
+    protected byte[] engineGetEncoded(
+        String format)
+    {
+        if (isASN1FormatString(format))
+        {
+            return engineGetEncoded();
+        }
+
+        return null;
+    }
+
+    protected AlgorithmParameterSpec localEngineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == DSAParameterSpec.class)
+        {
+            return currentSpec;
+        }
+
+        throw new InvalidParameterSpecException("unknown parameter spec passed to DSA parameters object.");
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (!(paramSpec instanceof DSAParameterSpec))
+        {
+            throw new InvalidParameterSpecException("DSAParameterSpec required to initialise a DSA algorithm parameters object");
+        }
+
+        this.currentSpec = (DSAParameterSpec)paramSpec;
+    }
+
+    protected void engineInit(
+        byte[] params)
+        throws IOException
+    {
+        try
+        {
+            DSAParameter dsaP = new DSAParameter((ASN1Sequence)ASN1Primitive.fromByteArray(params));
+
+            currentSpec = new DSAParameterSpec(dsaP.getP(), dsaP.getQ(), dsaP.getG());
+        }
+        catch (ClassCastException e)
+        {
+            throw new IOException("Not a valid DSA Parameter encoding.");
+        }
+        catch (ArrayIndexOutOfBoundsException e)
+        {
+            throw new IOException("Not a valid DSA Parameter encoding.");
+        }
+    }
+
+    protected void engineInit(
+        byte[] params,
+        String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+        {
+            engineInit(params);
+        }
+        else
+        {
+            throw new IOException("Unknown parameter format " + format);
+        }
+    }
+
+    protected String engineToString()
+    {
+        return "DSA Parameters";
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
new file mode 100644
index 0000000..f67d12d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCDSAPrivateKey
+    implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    private static final long serialVersionUID = -4677259546958385734L;
+
+    private BigInteger          x;
+    private transient DSAParams dsaSpec;
+
+    private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCDSAPrivateKey()
+    {
+    }
+
+    BCDSAPrivateKey(
+        DSAPrivateKey key)
+    {
+        this.x = key.getX();
+        this.dsaSpec = key.getParams();
+    }
+
+    BCDSAPrivateKey(
+        DSAPrivateKeySpec spec)
+    {
+        this.x = spec.getX();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    public BCDSAPrivateKey(
+        PrivateKeyInfo info)
+        throws IOException
+    {
+        DSAParameter    params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+        ASN1Integer      derX = (ASN1Integer)info.parsePrivateKey();
+
+        this.x = derX.getValue();
+        this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+    }
+
+    BCDSAPrivateKey(
+        DSAPrivateKeyParameters params)
+    {
+        this.x = params.getX();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(getX()));
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPrivateKey))
+        {
+            return false;
+        }
+        
+        DSAPrivateKey other = (DSAPrivateKey)o;
+        
+        return this.getX().equals(other.getX()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+
+    public int hashCode()
+    {
+        return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dsaSpec.getP());
+        out.writeObject(dsaSpec.getQ());
+        out.writeObject(dsaSpec.getG());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
new file mode 100644
index 0000000..e66330b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
@@ -0,0 +1,171 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCDSAPublicKey
+    implements DSAPublicKey
+{
+    private static final long serialVersionUID = 1752452449903495175L;
+
+    private BigInteger      y;
+    private transient DSAParams       dsaSpec;
+
+    BCDSAPublicKey(
+        DSAPublicKeySpec spec)
+    {
+        this.y = spec.getY();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    BCDSAPublicKey(
+        DSAPublicKey key)
+    {
+        this.y = key.getY();
+        this.dsaSpec = key.getParams();
+    }
+
+    BCDSAPublicKey(
+        DSAPublicKeyParameters params)
+    {
+        this.y = params.getY();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    BCDSAPublicKey(
+        BigInteger y,
+        DSAParameterSpec dsaSpec)
+    {
+        this.y = y;
+        this.dsaSpec = dsaSpec;
+    }
+
+    public BCDSAPublicKey(
+        SubjectPublicKeyInfo info)
+    {
+
+        ASN1Integer              derY;
+
+        try
+        {
+            derY = (ASN1Integer)info.parsePublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DSA public key");
+        }
+
+        this.y = derY.getValue();
+
+        if (isNotNull(info.getAlgorithm().getParameters()))
+        {
+            DSAParameter params = DSAParameter.getInstance(info.getAlgorithm().getParameters());
+            
+            this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+        }
+    }
+
+    private boolean isNotNull(ASN1Encodable parameters)
+    {
+        return parameters != null && !DERNull.INSTANCE.equals(parameters.toASN1Primitive());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        if (dsaSpec == null)
+        {
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(y));
+        }
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(y));
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("DSA Public Key").append(nl);
+        buf.append("            y: ").append(this.getY().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    public int hashCode()
+    {
+        return this.getY().hashCode() ^ this.getParams().getG().hashCode() 
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPublicKey))
+        {
+            return false;
+        }
+        
+        DSAPublicKey other = (DSAPublicKey)o;
+        
+        return this.getY().equals(other.getY()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dsaSpec.getP());
+        out.writeObject(dsaSpec.getQ());
+        out.writeObject(dsaSpec.getG());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
similarity index 71%
rename from src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
index 1c22952..e95b76d 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
 
 import java.io.IOException;
 import java.math.BigInteger;
@@ -11,31 +11,31 @@
 import java.security.interfaces.DSAKey;
 import java.security.spec.AlgorithmParameterSpec;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DSA;
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.digests.NullDigest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
 // BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
 // import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
 // END android-removed
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
 import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.crypto.signers.DSASigner;
-// BEGIN android-removed
-// import org.bouncycastle.jce.interfaces.GOST3410Key;
-// END android-removed
 
-public class JDKDSASigner
+public class DSASigner
     extends SignatureSpi
     implements PKCSObjectIdentifiers, X509ObjectIdentifiers
 {
@@ -43,9 +43,9 @@
     private DSA                     signer;
     private SecureRandom            random;
 
-    protected JDKDSASigner(
-        Digest                  digest,
-        DSA                     signer)
+    protected DSASigner(
+        Digest digest,
+        DSA signer)
     {
         this.digest = digest;
         this.signer = signer;
@@ -57,16 +57,12 @@
     {
         CipherParameters    param;
 
-        // BEGIN android-removed
-        // if (publicKey instanceof GOST3410Key)
-        // {
-        //     param = GOST3410Util.generatePublicKeyParameter(publicKey);
-        // }
-        // else if (publicKey instanceof DSAKey)
-        // END android-removed
-        // BEGIN android-added
+//        if (publicKey instanceof GOST3410Key)
+//        {
+//            param = GOST3410Util.generatePublicKeyParameter(publicKey);
+//        }
+//        else if (publicKey instanceof DSAKey)
         if (publicKey instanceof DSAKey)
-        // END android-added
         {
             param = DSAUtil.generatePublicKeyParameter(publicKey);
         }
@@ -76,7 +72,7 @@
             {
                 byte[]  bytes = publicKey.getEncoded();
 
-                publicKey = JDKKeyFactory.createPublicKeyFromDERStream(bytes);
+                publicKey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
 
                 if (publicKey instanceof DSAKey)
                 {
@@ -112,18 +108,14 @@
     {
         CipherParameters    param;
 
-        // BEGIN android-removed
-        // if (privateKey instanceof GOST3410Key)
-        // {
-        //     param = GOST3410Util.generatePrivateKeyParameter(privateKey);
-        // }
-        // else
-        // {
-        // END android-removed
+//        if (privateKey instanceof GOST3410Key)
+//        {
+//            param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+//        }
+//        else
+//        {
             param = DSAUtil.generatePrivateKeyParameter(privateKey);
-        // BEGIN android-removed
-        // }
-        // END android-removed
+//        }
 
         if (random != null)
         {
@@ -221,74 +213,76 @@
         BigInteger  s)
         throws IOException
     {
-        DERInteger[] rs = new DERInteger[]{ new DERInteger(r), new DERInteger(s) };
-        return new DERSequence(rs).getEncoded(ASN1Encodable.DER);
+        ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) };
+        return new DERSequence(rs).getEncoded(ASN1Encoding.DER);
     }
 
     private BigInteger[] derDecode(
         byte[]  encoding)
         throws IOException
     {
-        ASN1Sequence s = (ASN1Sequence)ASN1Object.fromByteArray(encoding);
+        ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
         return new BigInteger[]{
-            ((DERInteger)s.getObjectAt(0)).getValue(),
-            ((DERInteger)s.getObjectAt(1)).getValue()
+            ((ASN1Integer)s.getObjectAt(0)).getValue(),
+            ((ASN1Integer)s.getObjectAt(1)).getValue()
         };
     }
 
     static public class stdDSA
-        extends JDKDSASigner
+        extends DSASigner
     {
         public stdDSA()
         {
-            super(new SHA1Digest(), new DSASigner());
+            // BEGIN android-changed
+            super(new OpenSSLDigest.SHA1(), new org.bouncycastle.crypto.signers.DSASigner());
+            // END android-changed
         }
     }
-    
+
     // BEGIN android-removed
     // static public class dsa224
-    //     extends JDKDSASigner
+    //     extends DSASigner
     // {
     //     public dsa224()
     //     {
-    //         super(new SHA224Digest(), new DSASigner());
+    //         super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner());
     //     }
     // }
     //
     // static public class dsa256
-    //     extends JDKDSASigner
+    //     extends DSASigner
     // {
     //     public dsa256()
     //     {
-    //         super(new SHA256Digest(), new DSASigner());
+    //         super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
     //     }
     // }
     //
     // static public class dsa384
-    //     extends JDKDSASigner
+    //     extends DSASigner
     // {
     //     public dsa384()
     //     {
-    //         super(new SHA384Digest(), new DSASigner());
+    //         super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner());
     //     }
     // }
     //
     // static public class dsa512
-    //     extends JDKDSASigner
+    //     extends DSASigner
     // {
     //     public dsa512()
     //     {
-    //         super(new SHA512Digest(), new DSASigner());
+    //         super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
     //     }
     // }
     // END android-removed
 
     static public class noneDSA
-        extends JDKDSASigner
+        extends DSASigner
     {
         public noneDSA()
         {
-            super(new NullDigest(), new DSASigner());
+            super(new NullDigest(), new org.bouncycastle.crypto.signers.DSASigner());
         }
     }
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/DSAUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
similarity index 71%
rename from src/main/java/org/bouncycastle/jce/provider/DSAUtil.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
index 5cf3c22..5e940ec 100644
--- a/src/main/java/org/bouncycastle/jce/provider/DSAUtil.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
 
 import java.security.InvalidKeyException;
 import java.security.PrivateKey;
@@ -6,6 +6,9 @@
 import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.DSAPublicKey;
 
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import org.bouncycastle.crypto.params.DSAParameters;
 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
@@ -17,6 +20,26 @@
  */
 public class DSAUtil
 {
+    public static final ASN1ObjectIdentifier[] dsaOids =
+    {
+        X9ObjectIdentifiers.id_dsa,
+        OIWObjectIdentifiers.dsaWithSHA1
+    };
+
+    public static boolean isDsaOid(
+        ASN1ObjectIdentifier algOid)
+    {
+        for (int i = 0; i != dsaOids.length; i++)
+        {
+            if (algOid.equals(dsaOids[i]))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     static public AsymmetricKeyParameter generatePublicKeyParameter(
         PublicKey    key)
         throws InvalidKeyException
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
new file mode 100644
index 0000000..a36f3dd
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
@@ -0,0 +1,117 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+{
+    public KeyFactorySpi()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
+        {
+            DSAPublicKey k = (DSAPublicKey)key;
+
+            return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+        }
+        else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey)
+        {
+            java.security.interfaces.DSAPrivateKey k = (java.security.interfaces.DSAPrivateKey)key;
+
+            return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+        }
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DSAPublicKey)
+        {
+            return new BCDSAPublicKey((DSAPublicKey)key);
+        }
+        else if (key instanceof DSAPrivateKey)
+        {
+            return new BCDSAPrivateKey((DSAPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (DSAUtil.isDsaOid(algOid))
+        {
+            return new BCDSAPrivateKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (DSAUtil.isDsaOid(algOid))
+        {
+            return new BCDSAPublicKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DSAPrivateKeySpec)
+        {
+            return new BCDSAPrivateKey((DSAPrivateKeySpec)keySpec);
+        }
+
+        return super.engineGeneratePrivate(keySpec);
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DSAPublicKeySpec)
+        {
+            return new BCDSAPublicKey((DSAPublicKeySpec)keySpec);
+        }
+
+        return super.engineGeneratePublic(keySpec);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..c6ddf9b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
+import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
+public class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    DSAKeyGenerationParameters param;
+    DSAKeyPairGenerator engine = new DSAKeyPairGenerator();
+    int strength = 1024;
+    int certainty = 20;
+    SecureRandom random = new SecureRandom();
+    boolean initialised = false;
+
+    public KeyPairGeneratorSpi()
+    {
+        super("DSA");
+    }
+
+    public void initialize(
+        int strength,
+        SecureRandom random)
+    {
+        if (strength < 512 || strength > 1024 || strength % 64 != 0)
+        {
+            throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
+        }
+
+        this.strength = strength;
+        this.random = random;
+    }
+
+    public void initialize(
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof DSAParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec");
+        }
+        DSAParameterSpec dsaParams = (DSAParameterSpec)params;
+
+        param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
+
+        engine.init(param);
+        initialised = true;
+    }
+
+    public KeyPair generateKeyPair()
+    {
+        if (!initialised)
+        {
+            DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+            pGen.init(strength, certainty, random);
+            param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
+            engine.init(param);
+            initialised = true;
+        }
+
+        AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+        DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic();
+        DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
+
+        return new KeyPair(new BCDSAPublicKey(pub),
+            new BCDSAPrivateKey(priv));
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
new file mode 100644
index 0000000..b07912e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -0,0 +1,498 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+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;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// BEGIN android-removed
+// 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;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class BCECPrivateKey
+    implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+    static final long serialVersionUID = 994553197664784084L;
+
+    private String          algorithm = "EC";
+    private boolean         withCompression;
+
+    private transient BigInteger              d;
+    private transient ECParameterSpec         ecSpec;
+    private transient ProviderConfiguration   configuration;
+    private transient DERBitString            publicKey;
+
+    private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCECPrivateKey()
+    {
+    }
+
+    public BCECPrivateKey(
+        ECPrivateKey key,
+        ProviderConfiguration configuration)
+    {
+        this.d = key.getS();
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+        this.configuration = configuration;
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        org.bouncycastle.jce.spec.ECPrivateKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getD();
+
+        if (spec.getParams() != null) // can be null if implicitlyCA
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve;
+
+            ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            this.ecSpec = null;
+        }
+
+        this.configuration = configuration;
+    }
+
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getS();
+        this.ecSpec = spec.getParams();
+        this.configuration = configuration;
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        BCECPrivateKey key)
+    {
+        this.algorithm = algorithm;
+        this.d = key.d;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        this.attrCarrier = key.attrCarrier;
+        this.publicKey = key.publicKey;
+        this.configuration = key.configuration;
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeyParameters params,
+        BCECPublicKey pubKey,
+        ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.configuration = configuration;
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                            ellipticCurve,
+                            new ECPoint(
+                                    dp.getG().getX().toBigInteger(),
+                                    dp.getG().getY().toBigInteger()),
+                            dp.getN(),
+                            dp.getH().intValue());
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+
+        publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeyParameters params,
+        BCECPublicKey pubKey,
+        org.bouncycastle.jce.spec.ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.configuration = configuration;
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                            ellipticCurve,
+                            new ECPoint(
+                                    dp.getG().getX().toBigInteger(),
+                                    dp.getG().getY().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());
+        }
+
+        publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeyParameters params,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.ecSpec = null;
+        this.configuration = configuration;
+    }
+
+    BCECPrivateKey(
+        String         algorithm,
+        PrivateKeyInfo info,
+        ProviderConfiguration configuration)
+        throws IOException
+    {
+        this.algorithm = algorithm;
+        this.configuration = configuration;
+        populateFromPrivKeyInfo(info);
+    }
+
+    private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+        throws IOException
+    {
+        X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+
+        if (params.isNamedCurve())
+        {
+            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+            // 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());
+            }
+        }
+        else if (params.isImplicitlyCA())
+        {
+            ecSpec = null;
+        }
+        else
+        {
+            X9ECParameters      ecP = X9ECParameters.getInstance(params.getParameters());
+            EllipticCurve       ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                new ECPoint(
+                        ecP.getG().getX().toBigInteger(),
+                        ecP.getG().getY().toBigInteger()),
+                ecP.getN(),
+                ecP.getH().intValue());
+        }
+
+        ASN1Encodable privKey = info.parsePrivateKey();
+        if (privKey instanceof DERInteger)
+        {
+            DERInteger          derD = DERInteger.getInstance(privKey);
+
+            this.d = derD.getValue();
+        }
+        else
+        {
+            org.bouncycastle.asn1.sec.ECPrivateKey ec = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+            this.d = ec.getKey();
+            this.publicKey = ec.getPublicKey();
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        X962Parameters          params;
+
+        if (ecSpec instanceof ECNamedCurveSpec)
+        {
+            DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+            if (curveOid == null)  // guess it's the OID
+            {
+                curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+            }
+            params = new X962Parameters(curveOid);
+        }
+        else if (ecSpec == null)
+        {
+            params = new X962Parameters(DERNull.INSTANCE);
+        }
+        else
+        {
+            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+            X9ECParameters ecP = new X9ECParameters(
+                curve,
+                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+
+            params = new X962Parameters(ecP);
+        }
+        
+        PrivateKeyInfo          info;
+        org.bouncycastle.asn1.sec.ECPrivateKey            keyStructure;
+
+        if (publicKey != null)
+        {
+            keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(this.getS(), publicKey, params);
+        }
+        else
+        {
+            keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(this.getS(), params);
+        }
+
+        try
+        {
+            if (algorithm.equals("ECGOST3410"))
+            {
+                info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+            }
+            else
+            {
+
+                info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+            }
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)
+        {
+            return null;
+        }
+        
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return configuration.getEcImplicitlyCa();
+    }
+
+    public BigInteger getS()
+    {
+        return d;
+    }
+
+    public BigInteger getD()
+    {
+        return d;
+    }
+    
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof BCECPrivateKey))
+        {
+            return false;
+        }
+
+        BCECPrivateKey other = (BCECPrivateKey)o;
+
+        return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return getD().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("EC Private Key").append(nl);
+        buf.append("             S: ").append(this.d.toString(16)).append(nl);
+
+        return buf.toString();
+
+    }
+
+    private DERBitString getPublicKeyDetails(BCECPublicKey pub)
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+            return info.getPublicKeyData();
+        }
+        catch (IOException e)
+        {   // should never happen
+            return null;
+        }
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        byte[] enc = (byte[])in.readObject();
+
+        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+        this.configuration = BouncyCastleProvider.CONFIGURATION;
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(this.getEncoded());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
new file mode 100644
index 0000000..14cc9dc
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -0,0 +1,443 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class BCECPublicKey
+    implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+    static final long serialVersionUID = 2422789860422731812L;
+
+    private String    algorithm = "EC";
+    private boolean   withCompression;
+
+    private transient org.bouncycastle.math.ec.ECPoint q;
+    private transient ECParameterSpec         ecSpec;
+    private transient ProviderConfiguration   configuration;
+
+    public BCECPublicKey(
+        String algorithm,
+        BCECPublicKey key)
+    {
+        this.algorithm = algorithm;
+        this.q = key.q;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        this.configuration = key.configuration;
+    }
+    
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.ecSpec = spec.getParams();
+        this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+        this.configuration = configuration;
+    }
+
+    public BCECPublicKey(
+        String algorithm,
+        org.bouncycastle.jce.spec.ECPublicKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.q = spec.getQ();
+
+        if (spec.getParams() != null) // can be null if implictlyCa
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            if (q.getCurve() == null)
+            {
+                org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
+
+                q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+            }               
+            this.ecSpec = null;
+        }
+
+        this.configuration = configuration;
+    }
+    
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeyParameters params,
+        ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+
+        this.configuration = configuration;
+    }
+
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeyParameters params,
+        org.bouncycastle.jce.spec.ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+        }
+
+        this.configuration = configuration;
+    }
+
+    /*
+     * called for implicitCA
+     */
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeyParameters params,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+        this.ecSpec = null;
+        this.configuration = configuration;
+    }
+
+    public BCECPublicKey(
+        ECPublicKey key,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+        this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+    }
+
+    BCECPublicKey(
+        String algorithm,
+        SubjectPublicKeyInfo info,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.configuration = configuration;
+        populateFromPubKeyInfo(info);
+    }
+
+    private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+    {
+        return new ECParameterSpec(
+                ellipticCurve,
+                new ECPoint(
+                        dp.getG().getX().toBigInteger(),
+                        dp.getG().getY().toBigInteger()),
+                        dp.getN(),
+                        dp.getH().intValue());
+    }
+
+    private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+    {
+        X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithm().getParameters());
+        ECCurve                 curve;
+        EllipticCurve           ellipticCurve;
+
+        if (params.isNamedCurve())
+        {
+            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+            curve = ecP.getCurve();
+            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+            ecSpec = new ECNamedCurveSpec(
+                    ECUtil.getCurveName(oid),
+                    ellipticCurve,
+                    new ECPoint(
+                            ecP.getG().getX().toBigInteger(),
+                            ecP.getG().getY().toBigInteger()),
+                    ecP.getN(),
+                    ecP.getH());
+        }
+        else if (params.isImplicitlyCA())
+        {
+            ecSpec = null;
+            curve = configuration.getEcImplicitlyCa().getCurve();
+        }
+        else
+        {
+            X9ECParameters          ecP = X9ECParameters.getInstance(params.getParameters());
+
+            curve = ecP.getCurve();
+            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                    ellipticCurve,
+                    new ECPoint(
+                            ecP.getG().getX().toBigInteger(),
+                            ecP.getG().getY().toBigInteger()),
+                    ecP.getN(),
+                    ecP.getH().intValue());
+        }
+
+        DERBitString    bits = info.getPublicKeyData();
+        byte[]          data = bits.getBytes();
+        ASN1OctetString key = new DEROctetString(data);
+
+        //
+        // extra octet string - one of our old certs...
+        //
+        if (data[0] == 0x04 && data[1] == data.length - 2
+            && (data[2] == 0x02 || data[2] == 0x03))
+        {
+            int qLength = new X9IntegerConverter().getByteLength(curve);
+
+            if (qLength >= data.length - 3)
+            {
+                try
+                {
+                    key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+                }
+                catch (IOException ex)
+                {
+                    throw new IllegalArgumentException("error recovering public key");
+                }
+            }
+        }
+        X9ECPoint derQ = new X9ECPoint(curve, key);
+
+        this.q = derQ.getPoint();
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        ASN1Encodable        params;
+        SubjectPublicKeyInfo info;
+
+        if (ecSpec instanceof ECNamedCurveSpec)
+        {
+            ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+            if (curveOid == null)
+            {
+                curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+            }
+            params = new X962Parameters(curveOid);
+        }
+        else if (ecSpec == null)
+        {
+            params = new X962Parameters(DERNull.INSTANCE);
+        }
+        else
+        {
+            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+            X9ECParameters ecP = new X9ECParameters(
+                curve,
+                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+
+            params = new X962Parameters(ecP);
+        }
+
+        ECCurve curve = this.engineGetQ().getCurve();
+        ASN1OctetString p = (ASN1OctetString)
+            new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive();
+
+        info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+    }
+
+    private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+    {
+        byte[] val = bI.toByteArray();
+        if (val.length < 32)
+        {
+            byte[] tmp = new byte[32];
+            System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+            val = tmp;
+        }
+
+        for (int i = 0; i != 32; i++)
+        {
+            encKey[offSet + i] = val[val.length - 1 - i];
+        }
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)     // implictlyCA
+        {
+            return null;
+        }
+
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    public ECPoint getW()
+    {
+        return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
+    }
+
+    public org.bouncycastle.math.ec.ECPoint getQ()
+    {
+        if (ecSpec == null)
+        {
+            if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
+            {
+                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+            }
+            else
+            {
+                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+            }
+        }
+
+        return q;
+    }
+
+    public org.bouncycastle.math.ec.ECPoint engineGetQ()
+    {
+        return q;
+    }
+
+    org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return configuration.getEcImplicitlyCa();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        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);
+
+        return buf.toString();
+
+    }
+    
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof BCECPublicKey))
+        {
+            return false;
+        }
+
+        BCECPublicKey other = (BCECPublicKey)o;
+
+        return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        byte[] enc = (byte[])in.readObject();
+
+        populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+        this.configuration = BouncyCastleProvider.CONFIGURATION;
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(this.getEncoded());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/EC5Util.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java
similarity index 98%
rename from src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/EC5Util.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java
index b693613..38025e7 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/EC5Util.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider.asymmetric.ec;
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
 
 import java.math.BigInteger;
 import java.security.spec.ECField;
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java
similarity index 91%
rename from src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java
index 088dfad..80ff2af 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java
@@ -1,6 +1,10 @@
-package org.bouncycastle.jce.provider.asymmetric.ec;
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 // BEGIN android-removed
 // import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
 // END android-removed
@@ -17,13 +21,8 @@
 import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 import org.bouncycastle.jce.interfaces.ECPrivateKey;
 import org.bouncycastle.jce.interfaces.ECPublicKey;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.jce.spec.ECParameterSpec;
-import org.bouncycastle.jce.provider.ProviderUtil;
-import org.bouncycastle.jce.provider.JCEECPublicKey;
-
-import java.security.InvalidKeyException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
 
 /**
  * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
@@ -112,10 +111,10 @@
 
             if (s == null)
             {
-                s = ProviderUtil.getEcImplicitlyCa();
+                s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
 
                 return new ECPublicKeyParameters(
-                            ((JCEECPublicKey)k).engineGetQ(),
+                            ((BCECPublicKey)k).engineGetQ(),
                             new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
             }
             else
@@ -148,7 +147,7 @@
 
             if (s == null)
             {
-                s = ProviderUtil.getEcImplicitlyCa();
+                s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
             }
 
             return new ECPrivateKeyParameters(
@@ -159,10 +158,10 @@
         throw new InvalidKeyException("can't identify EC private key.");
     }
 
-    public static DERObjectIdentifier getNamedCurveOid(
+    public static ASN1ObjectIdentifier getNamedCurveOid(
         String name)
     {
-        DERObjectIdentifier oid = X962NamedCurves.getOID(name);
+        ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
         
         if (oid == null)
         {
@@ -187,7 +186,7 @@
     }
     
     public static X9ECParameters getNamedCurveByOid(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         X9ECParameters params = X962NamedCurves.getByOID(oid);
         
@@ -210,7 +209,7 @@
     }
 
     public static String getCurveName(
-        DERObjectIdentifier oid)
+        ASN1ObjectIdentifier oid)
     {
         String name = X962NamedCurves.getName(oid);
         
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
similarity index 95%
rename from src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
index 438928f..38a7143 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider.asymmetric.ec;
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
 
 import java.math.BigInteger;
 import java.security.InvalidAlgorithmParameterException;
@@ -11,7 +11,6 @@
 import java.security.spec.AlgorithmParameterSpec;
 import java.util.Hashtable;
 
-import javax.crypto.KeyAgreementSpi;
 import javax.crypto.SecretKey;
 import javax.crypto.ShortBufferException;
 import javax.crypto.spec.SecretKeySpec;
@@ -51,8 +50,8 @@
  *
  * Also, MQV key agreement per SEC-1
  */
-public class KeyAgreement
-    extends KeyAgreementSpi
+public class KeyAgreementSpi
+    extends javax.crypto.KeyAgreementSpi
 {
     private static final X9IntegerConverter converter = new X9IntegerConverter();
     private static final Hashtable algorithms = new Hashtable();
@@ -88,10 +87,10 @@
         return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
     }
 
-    protected KeyAgreement(
-        String              kaAlgorithm,
-        BasicAgreement      agreement,
-        DerivationFunction  kdf)
+    protected KeyAgreementSpi(
+        String kaAlgorithm,
+        BasicAgreement agreement,
+        DerivationFunction kdf)
     {
         this.kaAlgorithm = kaAlgorithm;
         this.agreement = agreement;
@@ -290,7 +289,7 @@
     }
 
     public static class DH
-        extends KeyAgreement
+        extends KeyAgreementSpi
     {
         public DH()
         {
@@ -300,7 +299,7 @@
 
     // BEGIN android-removed
     // public static class DHC
-    //     extends KeyAgreement
+    //     extends KeyAgreementSpi
     // {
     //     public DHC()
     //     {
@@ -309,7 +308,7 @@
     // }
     //
     // public static class MQV
-    //     extends KeyAgreement
+    //     extends KeyAgreementSpi
     // {
     //     public MQV()
     //     {
@@ -318,7 +317,7 @@
     // }
     //
     // public static class DHwithSHA1KDF
-    //     extends KeyAgreement
+    //     extends KeyAgreementSpi
     // {
     //     public DHwithSHA1KDF()
     //     {
@@ -327,7 +326,7 @@
     // }
     //
     // public static class MQVwithSHA1KDF
-    //     extends KeyAgreement
+    //     extends KeyAgreementSpi
     // {
     //     public MQVwithSHA1KDF()
     //     {
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
new file mode 100644
index 0000000..156b1d0
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -0,0 +1,240 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.jce.spec.ECPrivateKeySpec;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+    implements AsymmetricKeyInfoConverter
+{
+    String algorithm;
+    ProviderConfiguration configuration;
+
+    KeyFactorySpi(
+        String algorithm,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.configuration = configuration;
+    }
+
+    protected Key engineTranslateKey(
+        Key    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPublicKey)
+        {
+            return new BCECPublicKey((ECPublicKey)key, configuration);
+        }
+        else if (key instanceof ECPrivateKey)
+        {
+            return new BCECPrivateKey((ECPrivateKey)key, configuration);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key    key,
+        Class    spec)
+    throws InvalidKeySpecException
+    {
+       if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+       {
+           ECPublicKey k = (ECPublicKey)key;
+           if (k.getParams() != null)
+           {
+               return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+           }
+           else
+           {
+               ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+               return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+           }
+       }
+       else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+       {
+           ECPrivateKey k = (ECPrivateKey)key;
+
+           if (k.getParams() != null)
+           {
+               return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+           }
+           else
+           {
+               ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+               return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); 
+           }
+       }
+       else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+       {
+           ECPublicKey k = (ECPublicKey)key;
+           if (k.getParams() != null)
+           {
+               return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false));
+           }
+           else
+           {
+               ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+               return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec);
+           }
+       }
+       else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+       {
+           ECPrivateKey k = (ECPrivateKey)key;
+
+           if (k.getParams() != null)
+           {
+               return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false));
+           }
+           else
+           {
+               ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+               return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec);
+           }
+       }
+
+       return super.engineGetKeySpec(key, spec);
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof ECPrivateKeySpec)
+        {
+            return new BCECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec, configuration);
+        }
+        else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+        {
+            return new BCECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec, configuration);
+        }
+
+        return super.engineGeneratePrivate(keySpec);
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof ECPublicKeySpec)
+        {
+            return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+        }
+        else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+        {
+            return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration);
+        }
+
+        return super.engineGeneratePublic(keySpec);
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            return new BCECPrivateKey(algorithm, keyInfo, configuration);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            return new BCECPublicKey(algorithm, keyInfo, configuration);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public static class EC
+        extends KeyFactorySpi
+    {
+        public EC()
+        {
+            super("EC", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    public static class ECDSA
+        extends KeyFactorySpi
+    {
+        public ECDSA()
+        {
+            super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class ECGOST3410
+    //     extends KeyFactorySpi
+    // {
+    //     public ECGOST3410()
+    //     {
+    //         super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+    //     }
+    // }
+    // END android-removed
+
+    public static class ECDH
+        extends KeyFactorySpi
+    {
+        public ECDH()
+        {
+            super("ECDH", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    public static class ECDHC
+        extends KeyFactorySpi
+    {
+        public ECDHC()
+        {
+            super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    public static class ECMQV
+        extends KeyFactorySpi
+    {
+        public ECMQV()
+        {
+            super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
similarity index 62%
rename from src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
index ab104ed..31090ae 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider.asymmetric.ec;
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
 
 import java.math.BigInteger;
 import java.security.InvalidAlgorithmParameterException;
@@ -9,10 +9,7 @@
 import java.security.spec.ECGenParameterSpec;
 import java.util.Hashtable;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-// END android-removed
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.nist.NISTNamedCurves;
 import org.bouncycastle.asn1.sec.SECNamedCurves;
 // BEGIN android-removed
@@ -26,25 +23,24 @@
 import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
 import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
 import org.bouncycastle.crypto.params.ECPublicKeyParameters;
-import org.bouncycastle.jce.provider.JCEECPrivateKey;
-import org.bouncycastle.jce.provider.JCEECPublicKey;
-import org.bouncycastle.jce.provider.JDKKeyPairGenerator;
-import org.bouncycastle.jce.provider.ProviderUtil;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
 import org.bouncycastle.jce.spec.ECNamedCurveSpec;
 import org.bouncycastle.jce.spec.ECParameterSpec;
 import org.bouncycastle.math.ec.ECCurve;
 import org.bouncycastle.math.ec.ECPoint;
 
-public abstract class KeyPairGenerator
-    extends JDKKeyPairGenerator
+public abstract class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
 {
-    public KeyPairGenerator(String algorithmName)
+    public KeyPairGeneratorSpi(String algorithmName)
     {
         super(algorithmName);
     }
 
     public static class EC
-        extends KeyPairGenerator
+        extends KeyPairGeneratorSpi
     {
         ECKeyGenerationParameters   param;
         ECKeyPairGenerator          engine = new ECKeyPairGenerator();
@@ -54,6 +50,7 @@
         SecureRandom                random = new SecureRandom();
         boolean                     initialised = false;
         String                      algorithm;
+        ProviderConfiguration       configuration;
 
         static private Hashtable    ecParameters;
 
@@ -75,13 +72,16 @@
         {
             super("EC");
             this.algorithm = "EC";
+            this.configuration = BouncyCastleProvider.CONFIGURATION;
         }
 
         public EC(
-            String  algorithm)
+            String  algorithm,
+            ProviderConfiguration configuration)
         {
             super(algorithm);
             this.algorithm = algorithm;
+            this.configuration = configuration;
         }
 
         public void initialize(
@@ -97,14 +97,14 @@
             }
             // END android-added
             // BEGIN android-changed
-            this.ecParams = ecParameters.get(Integer.valueOf(strength));
+            ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integer.valueOf(strength));
             // END android-changed
 
             if (ecParams != null)
             {
                 try
                 {
-                    initialize((ECGenParameterSpec)ecParams, random);
+                    initialize(ecParams, random);
                 }
                 catch (InvalidAlgorithmParameterException e)
                 {
@@ -150,85 +150,73 @@
                 engine.init(param);
                 initialised = true;
             }
-            else if (params instanceof ECGenParameterSpec)
+            else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
             {
-                final String curveName = ((ECGenParameterSpec)params).getName();
+                String curveName;
 
-                // BEGIN android-removed
-                // if (this.algorithm.equals("ECGOST3410"))
-                // {
-                //     ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(curveName);
-                //     if (ecP == null)
-                //     {
-                //         throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
-                //     }
-                //
-                //     this.ecParams = new ECNamedCurveSpec(
-                //                                     curveName,
-                //                                     ecP.getCurve(),
-                //                                     ecP.getG(),
-                //                                     ecP.getN(),
-                //                                     ecP.getH(),
-                //                                     ecP.getSeed());
-                // }
-                // else
-                // END android-removed
+                if (params instanceof ECGenParameterSpec)
                 {
-                    X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
+                    curveName = ((ECGenParameterSpec)params).getName();
+                }
+                else
+                {
+                    curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+                }
+
+                X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
+                if (ecP == null)
+                {
+                    ecP = SECNamedCurves.getByName(curveName);
                     if (ecP == null)
                     {
-                        ecP = SECNamedCurves.getByName(curveName);
-                        if (ecP == null)
+                        ecP = NISTNamedCurves.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)
+                        try
                         {
-                            ecP = NISTNamedCurves.getByName(curveName);
+                            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);
+                            }
                         }
-                        // 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
-                            {
-                                DERObjectIdentifier oid = new DERObjectIdentifier(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);
                         }
                     }
+                }
 
-                    this.ecParams = new ECNamedCurveSpec(
+                this.ecParams = new ECNamedCurveSpec(
                             curveName,
                             ecP.getCurve(),
                             ecP.getG(),
                             ecP.getN(),
                             ecP.getH(),
-                            null); // ecP.getSeed());   Work-around JDK bug -- it won't look up named curves properly if seed is present 
-                }
+                            null); // ecP.getSeed());   Work-around JDK bug -- it won't look up named curves properly if seed is present
 
                 java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
 
@@ -240,9 +228,9 @@
                 engine.init(param);
                 initialised = true;
             }
-            else if (params == null && ProviderUtil.getEcImplicitlyCa() != null)
+            else if (params == null && configuration.getEcImplicitlyCa() != null)
             {
-                ECParameterSpec p = ProviderUtil.getEcImplicitlyCa();
+                ECParameterSpec p = configuration.getEcImplicitlyCa();
                 this.ecParams = params;
 
                 param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
@@ -250,7 +238,7 @@
                 engine.init(param);
                 initialised = true;
             }
-            else if (params == null && ProviderUtil.getEcImplicitlyCa() == null)
+            else if (params == null && configuration.getEcImplicitlyCa() == null)
             {
                 throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
             }
@@ -283,22 +271,22 @@
             {
                 ECParameterSpec p = (ECParameterSpec)ecParams;
 
-                JCEECPublicKey pubKey = new JCEECPublicKey(algorithm, pub, p);
+                BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
                 return new KeyPair(pubKey,
-                                   new JCEECPrivateKey(algorithm, priv, pubKey, p));
+                                   new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
             }
             else if (ecParams == null)
             {
-               return new KeyPair(new JCEECPublicKey(algorithm, pub),
-                                   new JCEECPrivateKey(algorithm, priv));
+               return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
+                                   new BCECPrivateKey(algorithm, priv, configuration));
             }
             else
             {
                 java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
 
-                JCEECPublicKey pubKey = new JCEECPublicKey(algorithm, pub, p);
+                BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
                 
-                return new KeyPair(pubKey, new JCEECPrivateKey(algorithm, priv, pubKey, p));
+                return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
             }
         }
     }
@@ -308,27 +296,16 @@
     {
         public ECDSA()
         {
-            super("ECDSA");
+            super("ECDSA", BouncyCastleProvider.CONFIGURATION);
         }
     }
 
-    // BEGIN android-removed
-    // public static class ECGOST3410
-    //     extends EC
-    // {
-    //     public ECGOST3410()
-    //     {
-    //         super("ECGOST3410");
-    //     }
-    // }
-    // END android-removed
-
     public static class ECDH
         extends EC
     {
         public ECDH()
         {
-            super("ECDH");
+            super("ECDH", BouncyCastleProvider.CONFIGURATION);
         }
     }
 
@@ -337,7 +314,7 @@
     {
         public ECDHC()
         {
-            super("ECDHC");
+            super("ECDHC", BouncyCastleProvider.CONFIGURATION);
         }
     }
 
@@ -346,7 +323,7 @@
     {
         public ECMQV()
         {
-            super("ECMQV");
+            super("ECMQV", BouncyCastleProvider.CONFIGURATION);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
similarity index 76%
rename from src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
index 0bb21f8..61cd513 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -1,47 +1,48 @@
-package org.bouncycastle.jce.provider.asymmetric.ec;
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
 
 import java.io.IOException;
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.SecureRandom;
 import java.security.interfaces.ECPublicKey;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DSA;
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.digests.NullDigest;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.SHA1Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
 // import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
 // END android-removed
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
 import org.bouncycastle.crypto.params.ParametersWithRandom;
 import org.bouncycastle.crypto.signers.ECDSASigner;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.signers.ECNRSigner;
 // END android-removed
+import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
+import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder;
 import org.bouncycastle.jce.interfaces.ECKey;
-import org.bouncycastle.jce.provider.DSABase;
-import org.bouncycastle.jce.provider.DSAEncoder;
-import org.bouncycastle.jce.provider.JDKKeyFactory;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
-public class Signature
+public class SignatureSpi
     extends DSABase
 {
-    Signature(Digest digest, DSA signer, DSAEncoder encoder)
+    SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder)
     {
         super(digest, signer, encoder);
     }
@@ -61,7 +62,7 @@
             {
                 byte[] bytes = publicKey.getEncoded();
 
-                publicKey = JDKKeyFactory.createPublicKeyFromDERStream(bytes);
+                publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
 
                 if (publicKey instanceof ECPublicKey)
                 {
@@ -83,8 +84,7 @@
     }
 
     protected void engineInitSign(
-        PrivateKey privateKey,
-        SecureRandom random)
+        PrivateKey privateKey)
         throws InvalidKeyException
     {
         CipherParameters param;
@@ -100,9 +100,9 @@
 
         digest.reset();
 
-        if (random != null)
+        if (appRandom != null)
         {
-            signer.init(true, new ParametersWithRandom(param, random));
+            signer.init(true, new ParametersWithRandom(param, appRandom));
         }
         else
         {
@@ -111,16 +111,18 @@
     }
 
     static public class ecDSA
-        extends Signature
+        extends SignatureSpi
     {
         public ecDSA()
         {
-            super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
+            // BEGIN android-changed
+            super(new OpenSSLDigest.SHA1(), new ECDSASigner(), new StdDSAEncoder());
+            // END android-changed
         }
     }
 
     static public class ecDSAnone
-        extends Signature
+        extends SignatureSpi
     {
         public ecDSAnone()
         {
@@ -130,7 +132,7 @@
 
     // BEGIN android-removed
     // static public class ecDSA224
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecDSA224()
     //     {
@@ -140,35 +142,41 @@
     // END android-removed
 
     static public class ecDSA256
-        extends Signature
+        extends SignatureSpi
     {
         public ecDSA256()
         {
-            super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
+            // BEGIN android-changed
+            super(new OpenSSLDigest.SHA256(), new ECDSASigner(), new StdDSAEncoder());
+            // END android-changed
         }
     }
 
     static public class ecDSA384
-        extends Signature
+        extends SignatureSpi
     {
         public ecDSA384()
         {
-            super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
+            // BEGIN android-changed
+            super(new OpenSSLDigest.SHA384(), new ECDSASigner(), new StdDSAEncoder());
+            // END android-changed
         }
     }
 
     static public class ecDSA512
-        extends Signature
+        extends SignatureSpi
     {
         public ecDSA512()
         {
-            super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+            // BEGIN android-changed
+            super(new OpenSSLDigest.SHA512(), new ECDSASigner(), new StdDSAEncoder());
+            // END android-changed
         }
     }
 
     // BEGIN android-removed
     // static public class ecDSARipeMD160
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecDSARipeMD160()
     //     {
@@ -177,7 +185,7 @@
     // }
     //
     // static public class ecNR
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecNR()
     //     {
@@ -186,7 +194,7 @@
     // }
     //
     // static public class ecNR224
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecNR224()
     //     {
@@ -195,7 +203,7 @@
     // }
     //
     // static public class ecNR256
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecNR256()
     //     {
@@ -204,7 +212,7 @@
     // }
     //
     // static public class ecNR384
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecNR384()
     //     {
@@ -213,7 +221,7 @@
     // }
     //
     // static public class ecNR512
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecNR512()
     //     {
@@ -222,7 +230,7 @@
     // }
     //
     // static public class ecCVCDSA
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecCVCDSA()
     //     {
@@ -231,7 +239,7 @@
     // }
     //
     // static public class ecCVCDSA224
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecCVCDSA224()
     //     {
@@ -240,7 +248,7 @@
     // }
     //
     // static public class ecCVCDSA256
-    //     extends Signature
+    //     extends SignatureSpi
     // {
     //     public ecCVCDSA256()
     //     {
@@ -262,14 +270,14 @@
             v.add(new DERInteger(r));
             v.add(new DERInteger(s));
 
-            return new DERSequence(v).getEncoded(ASN1Encodable.DER);
+            return new DERSequence(v).getEncoded(ASN1Encoding.DER);
         }
 
         public BigInteger[] decode(
             byte[] encoding)
             throws IOException
         {
-            ASN1Sequence s = (ASN1Sequence)ASN1Object.fromByteArray(encoding);
+            ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
             BigInteger[] sig = new BigInteger[2];
 
             sig[0] = ((DERInteger)s.getObjectAt(0)).getValue();
@@ -341,4 +349,4 @@
             return sig;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..99ac36c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,273 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.jcajce.provider.util.DigestFactory;
+
+public abstract class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+    protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+        throws InvalidParameterSpecException;
+
+    public static class OAEP
+        extends AlgorithmParametersSpi
+    {
+        OAEPParameterSpec currentSpec;
+    
+        /**
+         * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                            DigestFactory.getOID(currentSpec.getDigestAlgorithm()),
+                                                            // BEGIN android-changed
+                                                            DERNull.INSTANCE);
+                                                            // END android-changed
+            MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                            PKCSObjectIdentifiers.id_mgf1,
+                                                            // BEGIN android-changed
+                                                            new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+                                                            // END android-changed
+            PSource.PSpecified      pSource = (PSource.PSpecified)currentSpec.getPSource();
+            AlgorithmIdentifier pSourceAlgorithm = new AlgorithmIdentifier(
+                                                            PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+            RSAESOAEPparams oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
+    
+            try
+            {
+                return oaepP.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding OAEPParameters");
+            }
+        }
+    
+        protected byte[] engineGetEncoded(
+            String format)
+        {
+            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+            {
+                return engineGetEncoded();
+            }
+    
+            return null;
+        }
+    
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == OAEPParameterSpec.class && currentSpec != null)
+            {
+                return currentSpec;
+            }
+    
+            throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+        }
+    
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof OAEPParameterSpec))
+            {
+                throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
+            }
+    
+            this.currentSpec = (OAEPParameterSpec)paramSpec;
+        }
+    
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            try
+            {
+                RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+                currentSpec = new OAEPParameterSpec(
+                                       oaepP.getHashAlgorithm().getAlgorithm().getId(),
+                                       oaepP.getMaskGenAlgorithm().getAlgorithm().getId(), 
+                                       new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+                                       new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid OAEP Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid OAEP Parameter encoding.");
+            }
+        }
+    
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+    
+        protected String engineToString()
+        {
+            return "OAEP Parameters";
+        }
+    }
+    
+    public static class PSS
+        extends AlgorithmParametersSpi
+    {  
+        PSSParameterSpec currentSpec;
+    
+        /**
+         * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+         */
+        protected byte[] engineGetEncoded() 
+            throws IOException
+        {
+            PSSParameterSpec pssSpec = currentSpec;
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                DigestFactory.getOID(pssSpec.getDigestAlgorithm()),
+                                                // BEGIN android-changed
+                                                DERNull.INSTANCE);
+                                                // END android-changed
+            MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                PKCSObjectIdentifiers.id_mgf1,
+                                                // BEGIN android-changed
+                                                new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+                                                // END android-changed
+            RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField()));
+            
+            return pssP.getEncoded("DER");
+        }
+    
+        protected byte[] engineGetEncoded(
+            String format)
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+    
+            return null;
+        }
+    
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PSSParameterSpec.class && currentSpec != null)
+            {
+                return currentSpec;
+            }
+    
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+        }
+    
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PSSParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+            }
+    
+            this.currentSpec = (PSSParameterSpec)paramSpec;
+        }
+    
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            try
+            {
+                RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+                currentSpec = new PSSParameterSpec(
+                                       pssP.getHashAlgorithm().getAlgorithm().getId(), 
+                                       pssP.getMaskGenAlgorithm().getAlgorithm().getId(), 
+                                       new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+                                       pssP.getSaltLength().intValue(),
+                                       pssP.getTrailerField().intValue());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid PSS Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid PSS Parameter encoding.");
+            }
+        }
+    
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+    
+        protected String engineToString()
+        {
+            return "PSS Parameters";
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
new file mode 100644
index 0000000..b0aa66e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
@@ -0,0 +1,243 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class BCRSAPrivateCrtKey
+    extends BCRSAPrivateKey
+    implements RSAPrivateCrtKey
+{
+    static final long serialVersionUID = 7834723820638524718L;
+    
+    private BigInteger  publicExponent;
+    private BigInteger  primeP;
+    private BigInteger  primeQ;
+    private BigInteger  primeExponentP;
+    private BigInteger  primeExponentQ;
+    private BigInteger  crtCoefficient;
+
+    /**
+     * construct a private key from it's org.bouncycastle.crypto equivalent.
+     *
+     * @param key the parameters object representing the private key.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateCrtKeyParameters key)
+    {
+        super(key);
+
+        this.publicExponent = key.getPublicExponent();
+        this.primeP = key.getP();
+        this.primeQ = key.getQ();
+        this.primeExponentP = key.getDP();
+        this.primeExponentQ = key.getDQ();
+        this.crtCoefficient = key.getQInv();
+    }
+
+    /**
+     * construct a private key from an RSAPrivateCrtKeySpec
+     *
+     * @param spec the spec to be used in construction.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateCrtKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.publicExponent = spec.getPublicExponent();
+        this.privateExponent = spec.getPrivateExponent();
+        this.primeP = spec.getPrimeP();
+        this.primeQ = spec.getPrimeQ();
+        this.primeExponentP = spec.getPrimeExponentP();
+        this.primeExponentQ = spec.getPrimeExponentQ();
+        this.crtCoefficient = spec.getCrtCoefficient();
+    }
+
+    /**
+     * construct a private key from another RSAPrivateCrtKey.
+     *
+     * @param key the object implementing the RSAPrivateCrtKey interface.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateCrtKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+        this.privateExponent = key.getPrivateExponent();
+        this.primeP = key.getPrimeP();
+        this.primeQ = key.getPrimeQ();
+        this.primeExponentP = key.getPrimeExponentP();
+        this.primeExponentQ = key.getPrimeExponentQ();
+        this.crtCoefficient = key.getCrtCoefficient();
+    }
+
+    /**
+     * construct an RSA key from a private key info object.
+     */
+    BCRSAPrivateCrtKey(
+        PrivateKeyInfo info)
+        throws IOException
+    {
+        this(RSAPrivateKey.getInstance(info.parsePrivateKey()));
+    }
+
+    /**
+     * construct an RSA key from a ASN.1 RSA private key object.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+        this.privateExponent = key.getPrivateExponent();
+        this.primeP = key.getPrime1();
+        this.primeQ = key.getPrime2();
+        this.primeExponentP = key.getExponent1();
+        this.primeExponentQ = key.getExponent2();
+        this.crtCoefficient = key.getCoefficient();
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the encoding format we produce in getEncoded().
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        // BEGIN android-changed
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+        // END android-changed
+    }
+
+    /**
+     * return the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * return the prime P.
+     *
+     * @return the prime P.
+     */
+    public BigInteger getPrimeP()
+    {
+        return primeP;
+    }
+
+    /**
+     * return the prime Q.
+     *
+     * @return the prime Q.
+     */
+    public BigInteger getPrimeQ()
+    {
+        return primeQ;
+    }
+
+    /**
+     * return the prime exponent for P.
+     *
+     * @return the prime exponent for P.
+     */
+    public BigInteger getPrimeExponentP()
+    {
+        return primeExponentP;
+    }
+
+    /**
+     * return the prime exponent for Q.
+     *
+     * @return the prime exponent for Q.
+     */
+    public BigInteger getPrimeExponentQ()
+    {
+        return primeExponentQ;
+    }
+
+    /**
+     * return the CRT coefficient.
+     *
+     * @return the CRT coefficient.
+     */
+    public BigInteger getCrtCoefficient()
+    {
+        return crtCoefficient;
+    }
+
+    public int hashCode()
+    {
+        return this.getModulus().hashCode()
+               ^ this.getPublicExponent().hashCode()
+               ^ this.getPrivateExponent().hashCode();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof RSAPrivateCrtKey))
+        {
+            return false;
+        }
+
+        RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+        return this.getModulus().equals(key.getModulus())
+         && this.getPublicExponent().equals(key.getPublicExponent())
+         && this.getPrivateExponent().equals(key.getPrivateExponent())
+         && this.getPrimeP().equals(key.getPrimeP())
+         && this.getPrimeQ().equals(key.getPrimeQ())
+         && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+         && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+         && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("RSA Private CRT Key").append(nl);
+        buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
+        buf.append("    public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+        buf.append("   private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+        buf.append("             primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+        buf.append("             primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+        buf.append("     primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+        buf.append("     primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+        buf.append("     crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
new file mode 100644
index 0000000..6643f13
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCRSAPrivateKey
+    implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    static final long serialVersionUID = 5110188922551353628L;
+
+    private static BigInteger ZERO = BigInteger.valueOf(0);
+
+    protected BigInteger modulus;
+    protected BigInteger privateExponent;
+
+    private transient PKCS12BagAttributeCarrierImpl   attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCRSAPrivateKey()
+    {
+    }
+
+    BCRSAPrivateKey(
+        RSAKeyParameters key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getExponent();
+    }
+
+    BCRSAPrivateKey(
+        RSAPrivateKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.privateExponent = spec.getPrivateExponent();
+    }
+
+    BCRSAPrivateKey(
+        RSAPrivateKey key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getPrivateExponent();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public String getAlgorithm()
+    {
+        return "RSA";
+    }
+
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    public byte[] getEncoded()
+    {
+        // BEGIN android-changed
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+        // END android-changed
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof RSAPrivateKey))
+        {
+            return false;
+        }
+
+        if (o == this)
+        {
+            return true;
+        }
+
+        RSAPrivateKey key = (RSAPrivateKey)o;
+
+        return getModulus().equals(key.getModulus())
+            && getPrivateExponent().equals(key.getPrivateExponent());
+    }
+
+    public int hashCode()
+    {
+        return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
new file mode 100644
index 0000000..e57da4a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCRSAPublicKey
+    implements RSAPublicKey
+{
+    static final long serialVersionUID = 2675817738516720772L;
+    
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+
+    BCRSAPublicKey(
+        RSAKeyParameters key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getExponent();
+    }
+
+    BCRSAPublicKey(
+        RSAPublicKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.publicExponent = spec.getPublicExponent();
+    }
+
+    BCRSAPublicKey(
+        RSAPublicKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+    }
+
+    BCRSAPublicKey(
+        SubjectPublicKeyInfo info)
+    {
+        try
+        {
+            org.bouncycastle.asn1.pkcs.RSAPublicKey  pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey());
+
+            this.modulus = pubKey.getModulus();
+            this.publicExponent = pubKey.getPublicExponent();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in RSA public key");
+        }
+    }
+
+    /**
+     * return the modulus.
+     *
+     * @return the modulus.
+     */
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    /**
+     * return the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public String getAlgorithm()
+    {
+        return "RSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        // BEGIN android-changed
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
+        // END android-changed
+    }
+
+    public int hashCode()
+    {
+        return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof RSAPublicKey))
+        {
+            return false;
+        }
+
+        RSAPublicKey key = (RSAPublicKey)o;
+
+        return getModulus().equals(key.getModulus())
+            && getPublicExponent().equals(key.getPublicExponent());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("RSA Public Key").append(nl);
+        buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
+        buf.append("    public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
similarity index 84%
rename from src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index 50a0e41..1f53f5a 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
 
 import java.io.ByteArrayOutputStream;
 import java.security.AlgorithmParameters;
@@ -26,30 +26,36 @@
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
+// END android-removed
 import org.bouncycastle.crypto.encodings.OAEPEncoding;
 import org.bouncycastle.crypto.encodings.PKCS1Encoding;
 import org.bouncycastle.crypto.engines.RSABlindedEngine;
 import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.bouncycastle.jcajce.provider.util.DigestFactory;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.util.Strings;
 
-public class JCERSACipher extends WrapCipherSpi
+public class CipherSpi
+    extends BaseCipherSpi
 {
-    private AsymmetricBlockCipher   cipher;
-    private AlgorithmParameterSpec  paramSpec;
-    private AlgorithmParameters     engineParams;
+    private AsymmetricBlockCipher cipher;
+    private AlgorithmParameterSpec paramSpec;
+    private AlgorithmParameters engineParams;
     private boolean                 publicKeyOnly = false;
     private boolean                 privateKeyOnly = false;
-    private ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+    private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
 
-    public JCERSACipher(
-        AsymmetricBlockCipher   engine)
+    public CipherSpi(
+        AsymmetricBlockCipher engine)
     {
         cipher = engine;
     }
 
-    public JCERSACipher(
-        OAEPParameterSpec  pSpec)
+    public CipherSpi(
+        OAEPParameterSpec pSpec)
     {
         try
         {
@@ -61,10 +67,10 @@
         }
     }
 
-    public JCERSACipher(
-        boolean                 publicKeyOnly,
-        boolean                 privateKeyOnly,
-        AsymmetricBlockCipher   engine)
+    public CipherSpi(
+        boolean publicKeyOnly,
+        boolean privateKeyOnly,
+        AsymmetricBlockCipher engine)
     {
         this.publicKeyOnly = publicKeyOnly;
         this.privateKeyOnly = privateKeyOnly;
@@ -72,11 +78,11 @@
     }
      
     private void initFromSpec(
-        OAEPParameterSpec pSpec) 
+        OAEPParameterSpec pSpec)
         throws NoSuchPaddingException
     {
-        MGF1ParameterSpec   mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
-        Digest              digest = JCEDigestUtil.getDigest(mgfParams.getDigestAlgorithm());
+        MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+        Digest digest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
         
         if (digest == null)
         {
@@ -99,23 +105,18 @@
         }
     }
 
-    protected byte[] engineGetIV() 
-    {
-        return null;
-    }
-
     protected int engineGetKeySize(
-        Key     key) 
+        Key key)
     {
         if (key instanceof RSAPrivateKey)
         {
-            RSAPrivateKey   k = (RSAPrivateKey)key;
+            RSAPrivateKey k = (RSAPrivateKey)key;
 
             return k.getModulus().bitLength();
         }
         else if (key instanceof RSAPublicKey)
         {
-            RSAPublicKey   k = (RSAPublicKey)key;
+            RSAPublicKey k = (RSAPublicKey)key;
 
             return k.getModulus().bitLength();
         }
@@ -136,7 +137,7 @@
         }
     }
 
-    protected AlgorithmParameters engineGetParameters() 
+    protected AlgorithmParameters engineGetParameters()
     {
         if (engineParams == null)
         {
@@ -158,7 +159,7 @@
     }
 
     protected void engineSetMode(
-        String  mode)
+        String mode)
         throws NoSuchAlgorithmException
     {
         String md = Strings.toUpperCase(mode);
@@ -185,7 +186,7 @@
     }
 
     protected void engineSetPadding(
-        String  padding) 
+        String padding)
         throws NoSuchPaddingException
     {
         String pad = Strings.toUpperCase(padding);
@@ -198,10 +199,12 @@
         {
             cipher = new PKCS1Encoding(new RSABlindedEngine());
         }
-        else if (pad.equals("ISO9796-1PADDING"))
-        {
-            cipher = new ISO9796d1Encoding(new RSABlindedEngine());
-        }
+        // BEGIN android-removed
+        // else if (pad.equals("ISO9796-1PADDING"))
+        // {
+        //     cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+        // }
+        // END android-removed
         else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
         {
             initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
@@ -214,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));
@@ -238,18 +243,18 @@
 
     protected void engineInit(
         int                     opmode,
-        Key                     key,
-        AlgorithmParameterSpec  params,
-        SecureRandom            random) 
+        Key key,
+        AlgorithmParameterSpec params,
+        SecureRandom random)
     throws InvalidKeyException, InvalidAlgorithmParameterException
     {
-        CipherParameters        param;
+        CipherParameters param;
 
         if (params == null || params instanceof OAEPParameterSpec)
         {
             if (key instanceof RSAPublicKey)
             {
-                if (privateKeyOnly)
+                if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
                 {
                     throw new InvalidKeyException(
                                 "mode 1 requires RSAPrivateKey");
@@ -259,7 +264,7 @@
             }
             else if (key instanceof RSAPrivateKey)
             {
-                if (publicKeyOnly)
+                if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
                 {
                     throw new InvalidKeyException(
                                 "mode 2 requires RSAPublicKey");
@@ -274,7 +279,7 @@
             
             if (params != null)
             {
-                OAEPParameterSpec   spec = (OAEPParameterSpec)params;
+                OAEPParameterSpec spec = (OAEPParameterSpec)params;
                 
                 paramSpec = params;
                 
@@ -288,7 +293,7 @@
                     throw new InvalidAlgorithmParameterException("unkown MGF parameters");
                 }
     
-                Digest digest = JCEDigestUtil.getDigest(spec.getDigestAlgorithm());
+                Digest digest = DigestFactory.getDigest(spec.getDigestAlgorithm());
 
                 if (digest == null)
                 {
@@ -296,7 +301,7 @@
                 }
 
                 MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)spec.getMGFParameters();
-                Digest mgfDigest = JCEDigestUtil.getDigest(mgfParams.getDigestAlgorithm());
+                Digest mgfDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
                 
                 if (mgfDigest == null)
                 {
@@ -340,12 +345,12 @@
 
     protected void engineInit(
         int                 opmode,
-        Key                 key,
+        Key key,
         AlgorithmParameters params,
-        SecureRandom        random) 
+        SecureRandom random)
     throws InvalidKeyException, InvalidAlgorithmParameterException
     {
-        AlgorithmParameterSpec  paramSpec = null;
+        AlgorithmParameterSpec paramSpec = null;
 
         if (params != null)
         {
@@ -365,8 +370,8 @@
 
     protected void engineInit(
         int                 opmode,
-        Key                 key,
-        SecureRandom        random) 
+        Key key,
+        SecureRandom random)
     throws InvalidKeyException
     {
         try
@@ -376,7 +381,7 @@
         catch (InvalidAlgorithmParameterException e)
         {
             // this shouldn't happen
-            throw new RuntimeException("Eeeek! " + e.toString(), e);
+            throw new InvalidKeyException("Eeeek! " + e.toString(), e);
         }
     }
 
@@ -527,7 +532,7 @@
      */
 
     static public class NoPadding
-        extends JCERSACipher
+        extends CipherSpi
     {
         public NoPadding()
         {
@@ -537,7 +542,7 @@
 
     // BEGIN android-removed
     // static public class PKCS1v1_5Padding
-    //     extends JCERSACipher
+    //     extends CipherSpi
     // {
     //     public PKCS1v1_5Padding()
     //     {
@@ -546,7 +551,7 @@
     // }
     //
     // static public class PKCS1v1_5Padding_PrivateOnly
-    //     extends JCERSACipher
+    //     extends CipherSpi
     // {
     //     public PKCS1v1_5Padding_PrivateOnly()
     //     {
@@ -555,7 +560,7 @@
     // }
     //
     // static public class PKCS1v1_5Padding_PublicOnly
-    //     extends JCERSACipher
+    //     extends CipherSpi
     // {
     //     public PKCS1v1_5Padding_PublicOnly()
     //     {
@@ -564,7 +569,7 @@
     // }
     //
     // static public class OAEPPadding
-    //     extends JCERSACipher
+    //     extends CipherSpi
     // {
     //     public OAEPPadding()
     //     {
@@ -573,7 +578,7 @@
     // }
     //
     // static public class ISO9796d1Padding
-    //     extends JCERSACipher
+    //     extends CipherSpi
     // {
     //     public ISO9796d1Padding()
     //     {
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
similarity index 67%
rename from src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
index badeac1..96bd2d3 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
 
 import java.io.IOException;
 import java.security.AlgorithmParameters;
@@ -11,50 +11,51 @@
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.AlgorithmParameterSpec;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.DigestInfo;
-import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
 import org.bouncycastle.crypto.AsymmetricBlockCipher;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.Digest;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.MD2Digest;
 // import org.bouncycastle.crypto.digests.MD4Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.MD5Digest;
-import org.bouncycastle.crypto.digests.NullDigest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.NullDigest;
 // import org.bouncycastle.crypto.digests.RIPEMD128Digest;
 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
 // import org.bouncycastle.crypto.digests.RIPEMD256Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.SHA1Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
 // import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
 // END android-removed
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
 import org.bouncycastle.crypto.encodings.PKCS1Encoding;
 import org.bouncycastle.crypto.engines.RSABlindedEngine;
 
-public class JDKDigestSignature
+public class DigestSignatureSpi
     extends SignatureSpi
 {
-    private Digest                  digest;
-    private AsymmetricBlockCipher   cipher;
-    private AlgorithmIdentifier     algId;
+    private Digest digest;
+    private AsymmetricBlockCipher cipher;
+    private AlgorithmIdentifier algId;
 
     // care - this constructor is actually used by outside organisations
-    protected JDKDigestSignature(
-        Digest                  digest,
-        AsymmetricBlockCipher   cipher)
+    protected DigestSignatureSpi(
+        Digest digest,
+        AsymmetricBlockCipher cipher)
     {
         this.digest = digest;
         this.cipher = cipher;
@@ -62,10 +63,10 @@
     }
 
     // care - this constructor is actually used by outside organisations
-    protected JDKDigestSignature(
-        DERObjectIdentifier     objId,
-        Digest                  digest,
-        AsymmetricBlockCipher   cipher)
+    protected DigestSignatureSpi(
+        ASN1ObjectIdentifier objId,
+        Digest digest,
+        AsymmetricBlockCipher cipher)
     {
         this.digest = digest;
         this.cipher = cipher;
@@ -73,7 +74,7 @@
     }
 
     protected void engineInitVerify(
-        PublicKey   publicKey)
+        PublicKey publicKey)
         throws InvalidKeyException
     {
         if (!(publicKey instanceof RSAPublicKey))
@@ -81,14 +82,14 @@
             throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
         }
 
-        CipherParameters    param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+        CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
 
         digest.reset();
         cipher.init(false, param);
     }
 
     protected void engineInitSign(
-        PrivateKey  privateKey)
+        PrivateKey privateKey)
         throws InvalidKeyException
     {
         if (!(privateKey instanceof RSAPrivateKey))
@@ -96,7 +97,7 @@
             throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
         }
 
-        CipherParameters    param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+        CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
 
         digest.reset();
 
@@ -227,8 +228,8 @@
      * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
      */
     protected void engineSetParameter(
-        String  param,
-        Object  value)
+        String param,
+        Object value)
     {
         throw new UnsupportedOperationException("engineSetParameter unsupported");
     }
@@ -237,7 +238,7 @@
      * @deprecated
      */
     protected Object engineGetParameter(
-        String      param)
+        String param)
     {
         return null;
     }
@@ -257,117 +258,127 @@
             return hash;
         }
 
-        DigestInfo              dInfo = new DigestInfo(algId, hash);
+        DigestInfo dInfo = new DigestInfo(algId, hash);
 
-        return dInfo.getEncoded(ASN1Encodable.DER);
+        return dInfo.getEncoded(ASN1Encoding.DER);
     }
 
-    static public class SHA1WithRSAEncryption
-        extends JDKDigestSignature
+    static public class SHA1
+        extends DigestSignatureSpi
     {
-        public SHA1WithRSAEncryption()
+        public SHA1()
         {
-            super(X509ObjectIdentifiers.id_SHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+            // BEGIN android-changed
+            super(OIWObjectIdentifiers.idSHA1, new OpenSSLDigest.SHA1(), new PKCS1Encoding(new RSABlindedEngine()));
+            // END android-changed
         }
     }
 
     // BEGIN android-removed
-    // static public class SHA224WithRSAEncryption
-    //     extends JDKDigestSignature
+    // static public class SHA224
+    //     extends DigestSignatureSpi
     // {
-    //     public SHA224WithRSAEncryption()
+    //     public SHA224()
     //     {
     //         super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
     //     }
     // }
     // END android-removed
 
-    static public class SHA256WithRSAEncryption
-        extends JDKDigestSignature
+    static public class SHA256
+        extends DigestSignatureSpi
     {
-        public SHA256WithRSAEncryption()
+        public SHA256()
         {
-            super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+            // BEGIN android-changed
+            super(NISTObjectIdentifiers.id_sha256, new OpenSSLDigest.SHA256(), new PKCS1Encoding(new RSABlindedEngine()));
+            // END android-changed
         }
     }
 
-    static public class SHA384WithRSAEncryption
-        extends JDKDigestSignature
+    static public class SHA384
+        extends DigestSignatureSpi
     {
-        public SHA384WithRSAEncryption()
+        public SHA384()
         {
-            super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+            // BEGIN android-changed
+            super(NISTObjectIdentifiers.id_sha384, new OpenSSLDigest.SHA384(), new PKCS1Encoding(new RSABlindedEngine()));
+            // END android-changed
         }
     }
 
-    static public class SHA512WithRSAEncryption
-        extends JDKDigestSignature
+    static public class SHA512
+        extends DigestSignatureSpi
     {
-        public SHA512WithRSAEncryption()
+        public SHA512()
         {
-            super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+            // BEGIN android-changed
+            super(NISTObjectIdentifiers.id_sha512, new OpenSSLDigest.SHA512(), new PKCS1Encoding(new RSABlindedEngine()));
+            // END android-changed
         }
     }
 
     // BEGIN android-removed
-    // static public class MD2WithRSAEncryption
-    //     extends JDKDigestSignature
+    // static public class MD2
+    //     extends DigestSignatureSpi
     // {
-    //     public MD2WithRSAEncryption()
+    //     public MD2()
     //     {
     //         super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
     //     }
     // }
     //
-    // static public class MD4WithRSAEncryption
-    //     extends JDKDigestSignature
+    // static public class MD4
+    //     extends DigestSignatureSpi
     // {
-    //     public MD4WithRSAEncryption()
+    //     public MD4()
     //     {
     //         super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
     //     }
     // }
     // END android-removed
 
-    static public class MD5WithRSAEncryption
-        extends JDKDigestSignature
+    static public class MD5
+        extends DigestSignatureSpi
     {
-        public MD5WithRSAEncryption()
+        public MD5()
         {
-            super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+            // BEGIN android-changed
+            super(PKCSObjectIdentifiers.md5, new OpenSSLDigest.MD5(), new PKCS1Encoding(new RSABlindedEngine()));
+            // END android-changed
         }
     }
 
     // BEGIN android-removed
-    // static public class RIPEMD160WithRSAEncryption
-    //     extends JDKDigestSignature
+    // static public class RIPEMD160
+    //     extends DigestSignatureSpi
     // {
-    //     public RIPEMD160WithRSAEncryption()
+    //     public RIPEMD160()
     //     {
     //         super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
     //     }
     // }
     //
-    // static public class RIPEMD128WithRSAEncryption
-    //     extends JDKDigestSignature
+    // static public class RIPEMD128
+    //     extends DigestSignatureSpi
     // {
-    //     public RIPEMD128WithRSAEncryption()
+    //     public RIPEMD128()
     //     {
     //         super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
     //     }
     // }
     //
-    // static public class RIPEMD256WithRSAEncryption
-    //     extends JDKDigestSignature
+    // static public class RIPEMD256
+    //     extends DigestSignatureSpi
     // {
-    //     public RIPEMD256WithRSAEncryption()
+    //     public RIPEMD256()
     //     {
     //         super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
     //     }
     // }
     //
     // static public class noneRSA
-    //     extends JDKDigestSignature
+    //     extends DigestSignatureSpi
     // {
     //     public noneRSA()
     //     {
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
new file mode 100644
index 0000000..d8eb539
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
@@ -0,0 +1,162 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
+
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+{
+    public KeyFactorySpi()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
+        {
+            RSAPublicKey k = (RSAPublicKey)key;
+
+            return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
+        }
+        else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof java.security.interfaces.RSAPrivateKey)
+        {
+            java.security.interfaces.RSAPrivateKey k = (java.security.interfaces.RSAPrivateKey)key;
+
+            return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
+        }
+        else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
+        {
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+            return new RSAPrivateCrtKeySpec(
+                k.getModulus(), k.getPublicExponent(),
+                k.getPrivateExponent(),
+                k.getPrimeP(), k.getPrimeQ(),
+                k.getPrimeExponentP(), k.getPrimeExponentQ(),
+                k.getCrtCoefficient());
+        }
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof RSAPublicKey)
+        {
+            return new BCRSAPublicKey((RSAPublicKey)key);
+        }
+        else if (key instanceof RSAPrivateCrtKey)
+        {
+            return new BCRSAPrivateCrtKey((RSAPrivateCrtKey)key);
+        }
+        else if (key instanceof java.security.interfaces.RSAPrivateKey)
+        {
+            return new BCRSAPrivateKey((java.security.interfaces.RSAPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+            }
+            catch (Exception e)
+            {
+                //
+                // in case it's just a RSAPrivateKey object... -- openSSL produces these
+                //
+                try
+                {
+                    return new BCRSAPrivateCrtKey(
+                        RSAPrivateKey.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+                }
+                catch (Exception ex)
+                {
+                    throw new ExtendedInvalidKeySpecException("unable to process key spec: " + e.toString(), e);
+                }
+            }
+        }
+        else if (keySpec instanceof RSAPrivateCrtKeySpec)
+        {
+            return new BCRSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
+        }
+        else if (keySpec instanceof RSAPrivateKeySpec)
+        {
+            return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec);
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof RSAPublicKeySpec)
+        {
+            return new BCRSAPublicKey((RSAPublicKeySpec)keySpec);
+        }
+
+        return super.engineGeneratePublic(keySpec);
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (RSAUtil.isRsaOid(algOid))
+        {
+            return new BCRSAPrivateCrtKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (RSAUtil.isRsaOid(algOid))
+        {
+            return new BCRSAPublicKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..c61e7cb
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+public class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    public KeyPairGeneratorSpi(
+        String algorithmName)
+    {
+        super(algorithmName);
+    }
+
+    final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
+    final static int defaultTests = 12;
+
+    RSAKeyGenerationParameters param;
+    RSAKeyPairGenerator engine;
+
+    public KeyPairGeneratorSpi()
+    {
+        super("RSA");
+
+        engine = new RSAKeyPairGenerator();
+        param = new RSAKeyGenerationParameters(defaultPublicExponent,
+            new SecureRandom(), 2048, defaultTests);
+        engine.init(param);
+    }
+
+    public void initialize(
+        int strength,
+        SecureRandom random)
+    {
+        param = new RSAKeyGenerationParameters(defaultPublicExponent,
+            random, strength, defaultTests);
+
+        engine.init(param);
+    }
+
+    public void initialize(
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof RSAKeyGenParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
+        }
+        RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
+
+        param = new RSAKeyGenerationParameters(
+            rsaParams.getPublicExponent(),
+            random, rsaParams.getKeysize(), defaultTests);
+
+        engine.init(param);
+    }
+
+    public KeyPair generateKeyPair()
+    {
+        AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+        RSAKeyParameters pub = (RSAKeyParameters)pair.getPublic();
+        RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
+
+        return new KeyPair(new BCRSAPublicKey(pub),
+            new BCRSAPrivateCrtKey(priv));
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
new file mode 100644
index 0000000..4943a99
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * utility class for converting java.security RSA objects into their
+ * org.bouncycastle.crypto counterparts.
+ */
+public class RSAUtil
+{
+    public static final ASN1ObjectIdentifier[] rsaOids =
+    {
+        PKCSObjectIdentifiers.rsaEncryption,
+        X509ObjectIdentifiers.id_ea_rsa,
+        PKCSObjectIdentifiers.id_RSAES_OAEP,
+        PKCSObjectIdentifiers.id_RSASSA_PSS
+    };
+
+    public static boolean isRsaOid(
+        ASN1ObjectIdentifier algOid)
+    {
+        for (int i = 0; i != rsaOids.length; i++)
+        {
+            if (algOid.equals(rsaOids[i]))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    static RSAKeyParameters generatePublicKeyParameter(
+        RSAPublicKey key)
+    {
+        return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
+
+    }
+
+    static RSAKeyParameters generatePrivateKeyParameter(
+        RSAPrivateKey key)
+    {
+        if (key instanceof RSAPrivateCrtKey)
+        {
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+            return new RSAPrivateCrtKeyParameters(k.getModulus(),
+                k.getPublicExponent(), k.getPrivateExponent(),
+                k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient());
+        }
+        else
+        {
+            RSAPrivateKey k = key;
+
+            return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
new file mode 100644
index 0000000..fabad43
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
@@ -0,0 +1,220 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+// END android-removed
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public abstract class BaseCipherSpi
+    extends CipherSpi
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        // BEGIN android-removed
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class
+                                        // END android-removed
+                                    };
+
+
+    protected AlgorithmParameters     engineParams = null;
+
+    protected Wrapper                 wrapEngine = null;
+
+    private int                       ivSize;
+    private byte[]                    iv;
+
+    protected BaseCipherSpi()
+    {
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return -1;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        return null;
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        throw new NoSuchAlgorithmException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+    }
+
+    protected byte[] engineWrap(
+        Key     key)
+    throws IllegalBlockSizeException, InvalidKeyException
+    {
+        byte[] encoded = key.getEncoded();
+        if (encoded == null)
+        {
+            throw new InvalidKeyException("Cannot wrap key, null encoding.");
+        }
+
+        try
+        {
+            if (wrapEngine == null)
+            {
+                return engineDoFinal(encoded, 0, encoded.length);
+            }
+            else
+            {
+                return wrapEngine.wrap(encoded, 0, encoded.length);
+            }
+        }
+        catch (BadPaddingException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+    }
+
+    protected Key engineUnwrap(
+        byte[]  wrappedKey,
+        String  wrappedKeyAlgorithm,
+        int     wrappedKeyType)
+    throws InvalidKeyException
+    {
+        byte[] encoded;
+        try
+        {
+            if (wrapEngine == null)
+            {
+                encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+            }
+            else
+            {
+                encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+            }
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (BadPaddingException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (IllegalBlockSizeException e2)
+        {
+            throw new InvalidKeyException(e2.getMessage());
+        }
+
+        if (wrappedKeyType == Cipher.SECRET_KEY)
+        {
+            return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+        }
+        else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+        {
+            /*
+                 * The caller doesn't know the algorithm as it is part of
+                 * the encrypted data.
+                 */
+            try
+            {
+                PrivateKeyInfo       in = PrivateKeyInfo.getInstance(encoded);
+
+                PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+                if (privKey != null)
+                {
+                    return privKey;
+                }
+                else
+                {
+                    throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("Invalid key encoding.");
+            }
+        }
+        else
+        {
+            try
+            {
+                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+                if (wrappedKeyType == Cipher.PUBLIC_KEY)
+                {
+                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
+                }
+                else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+                {
+                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+                }
+            }
+            catch (NoSuchProviderException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (InvalidKeySpecException e2)
+            {
+                throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+            }
+
+            throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
new file mode 100644
index 0000000..e83e0ff
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public abstract class BaseKeyFactorySpi
+    extends java.security.KeyFactorySpi
+    implements AsymmetricKeyInfoConverter
+{
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+            }
+            catch (IOException e)
+            {
+                throw new InvalidKeySpecException("encoded key spec not recognised");
+            }
+        }
+        else
+        {
+            throw new InvalidKeySpecException("key spec not recognised");
+        }
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof X509EncodedKeySpec)
+        {
+            try
+            {
+                return generatePublic(SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded()));
+            }
+            catch (IOException e)
+            {
+                throw new InvalidKeySpecException("encoded key spec not recognised");
+            }
+        }
+        else
+        {
+            throw new InvalidKeySpecException("key spec not recognised");
+        }
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+        {
+            return new PKCS8EncodedKeySpec(key.getEncoded());
+        }
+        else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+        {
+            return new X509EncodedKeySpec(key.getEncoded());
+        }
+
+        throw new InvalidKeySpecException("not implemented yet " + key + " " + spec);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/DSABase.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
similarity index 89%
rename from src/main/java/org/bouncycastle/jce/provider/DSABase.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
index b30c11e..463de89 100644
--- a/src/main/java/org/bouncycastle/jce/provider/DSABase.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -1,10 +1,8 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.util;
 
 import java.math.BigInteger;
 import java.security.SignatureException;
 import java.security.SignatureSpi;
-import java.security.PrivateKey;
-import java.security.InvalidKeyException;
 import java.security.spec.AlgorithmParameterSpec;
 
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -16,7 +14,7 @@
     extends SignatureSpi
     implements PKCSObjectIdentifiers, X509ObjectIdentifiers
 {
-    protected Digest                  digest;
+    protected Digest digest;
     protected DSA                     signer;
     protected DSAEncoder              encoder;
 
@@ -30,13 +28,6 @@
         this.encoder = encoder;
     }
 
-    protected void engineInitSign(
-        PrivateKey privateKey)
-    throws InvalidKeyException
-    {
-        engineInitSign(privateKey, null);
-    }
-
     protected void engineUpdate(
         byte    b)
         throws SignatureException
diff --git a/src/main/java/org/bouncycastle/jce/provider/DSAEncoder.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
similarity index 79%
rename from src/main/java/org/bouncycastle/jce/provider/DSAEncoder.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
index e0dc92b..4ea0ff9 100644
--- a/src/main/java/org/bouncycastle/jce/provider/DSAEncoder.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
@@ -1,7 +1,7 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.util;
 
-import java.math.BigInteger;
 import java.io.IOException;
+import java.math.BigInteger;
 
 public interface DSAEncoder
 {
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
new file mode 100644
index 0000000..7945639
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+
+public class ExtendedInvalidKeySpecException
+    extends InvalidKeySpecException
+{
+    private Throwable cause;
+
+    public ExtendedInvalidKeySpecException(String msg, Throwable cause)
+    {
+        super(msg);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java
new file mode 100644
index 0000000..4dff91a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class KeyUtil
+{
+    public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, ASN1Encodable keyData)
+    {
+        try
+        {
+            return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, byte[] keyData)
+    {
+        try
+        {
+            return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public static byte[] getEncodedSubjectPublicKeyInfo(SubjectPublicKeyInfo info)
+    {
+         try
+         {
+             return info.getEncoded(ASN1Encoding.DER);
+         }
+         catch (Exception e)
+         {
+             return null;
+         }
+    }
+
+    public static byte[] getEncodedPrivateKeyInfo(AlgorithmIdentifier algId, ASN1Encodable privKey)
+    {
+         try
+         {
+             PrivateKeyInfo info = new PrivateKeyInfo(algId, privKey.toASN1Primitive());
+
+             return getEncodedPrivateKeyInfo(info);
+         }
+         catch (Exception e)
+         {
+             return null;
+         }
+    }
+
+    public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
+    {
+         try
+         {
+             return info.getEncoded(ASN1Encoding.DER);
+         }
+         catch (Exception e)
+         {
+             return null;
+         }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
similarity index 82%
rename from src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
index 984283f..06ccd66 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
@@ -1,20 +1,21 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.util;
 
-import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.ASN1OutputStream;
-import org.bouncycastle.asn1.ASN1InputStream;
-
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Vector;
-import java.io.ObjectOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
 
-class PKCS12BagAttributeCarrierImpl
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class PKCS12BagAttributeCarrierImpl
     implements PKCS12BagAttributeCarrier
 {
     private Hashtable pkcs12Attributes;
@@ -32,8 +33,8 @@
     }
 
     public void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
     {
         if (pkcs12Attributes.containsKey(oid))
         {                           // preserve original ordering
@@ -46,10 +47,10 @@
         }
     }
 
-    public DEREncodable getBagAttribute(
+    public ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid)
     {
-        return (DEREncodable)pkcs12Attributes.get(oid);
+        return (ASN1Encodable)pkcs12Attributes.get(oid);
     }
 
     public Enumeration getBagAttributeKeys()
@@ -92,7 +93,7 @@
                 DERObjectIdentifier    oid = (DERObjectIdentifier)e.nextElement();
 
                 aOut.writeObject(oid);
-                aOut.writeObject(pkcs12Attributes.get(oid));
+                aOut.writeObject((ASN1Encodable)pkcs12Attributes.get(oid));
             }
 
             out.writeObject(bOut.toByteArray());
@@ -113,9 +114,9 @@
         {
             ASN1InputStream aIn = new ASN1InputStream((byte[])obj);
 
-            DERObjectIdentifier    oid;
+            ASN1ObjectIdentifier    oid;
 
-            while ((oid = (DERObjectIdentifier)aIn.readObject()) != null)
+            while ((oid = (ASN1ObjectIdentifier)aIn.readObject()) != null)
             {
                 this.setBagAttribute(oid, aIn.readObject());
             }
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKX509CertificateFactory.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
similarity index 78%
rename from src/main/java/org/bouncycastle/jce/provider/JDKX509CertificateFactory.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
index 45eab83..33f3db7 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKX509CertificateFactory.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -1,14 +1,4 @@
-package org.bouncycastle.jce.provider;
-
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.SignedData;
-import org.bouncycastle.asn1.x509.CertificateList;
-import org.bouncycastle.asn1.x509.X509CertificateStructure;
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -16,7 +6,6 @@
 import java.security.cert.CRL;
 import java.security.cert.CRLException;
 import java.security.cert.CertPath;
-import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactorySpi;
 import java.security.cert.CertificateParsingException;
@@ -26,6 +15,18 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.SignedData;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.jce.provider.X509CRLObject;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+
 /**
  * class for dealing with X509 certificates.
  * <p>
@@ -33,33 +34,33 @@
  * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
  * objects.
  */
-public class JDKX509CertificateFactory
+public class CertificateFactory
     extends CertificateFactorySpi
 {
     private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
     private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
 
-    private ASN1Set            sData = null;
+    private ASN1Set sData = null;
     private int                sDataObjectCount = 0;
-    private InputStream        currentStream = null;
+    private InputStream currentStream = null;
     
-    private ASN1Set            sCrlData = null;
+    private ASN1Set sCrlData = null;
     private int                sCrlDataObjectCount = 0;
-    private InputStream        currentCrlStream = null;
+    private InputStream currentCrlStream = null;
 
-    private Certificate readDERCertificate(
+    private java.security.cert.Certificate readDERCertificate(
         ASN1InputStream dIn)
         throws IOException, CertificateParsingException
     {
-        ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+        ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
 
         if (seq.size() > 1
-                && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+                && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
         {
             if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
             {
-                sData = new SignedData(ASN1Sequence.getInstance(
-                                (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+                sData = SignedData.getInstance(ASN1Sequence.getInstance(
+                    (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
 
                 return getCertificate();
             }
@@ -69,7 +70,7 @@
                             X509CertificateStructure.getInstance(seq));
     }
 
-    private Certificate getCertificate()
+    private java.security.cert.Certificate getCertificate()
         throws CertificateParsingException
     {
         if (sData != null)
@@ -89,8 +90,8 @@
         return null;
     }
 
-    private Certificate readPEMCertificate(
-        InputStream  in)
+    private java.security.cert.Certificate readPEMCertificate(
+        InputStream in)
         throws IOException, CertificateParsingException
     {
         ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
@@ -111,7 +112,7 @@
     }
     
     private CRL readPEMCRL(
-        InputStream  in)
+        InputStream in)
         throws IOException, CRLException
     {
         ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
@@ -126,18 +127,18 @@
     }
 
     private CRL readDERCRL(
-        ASN1InputStream  aIn)
+        ASN1InputStream aIn)
         throws IOException, CRLException
     {
-        ASN1Sequence     seq = (ASN1Sequence)aIn.readObject();
+        ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
 
         if (seq.size() > 1
-                && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+                && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
         {
             if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
             {
-                sCrlData = new SignedData(ASN1Sequence.getInstance(
-                                (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+                sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+                    (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
     
                 return getCRL();
             }
@@ -157,15 +158,15 @@
 
         return createCRL(
                             CertificateList.getInstance(
-                                    sCrlData.getObjectAt(sCrlDataObjectCount++)));
+                                sCrlData.getObjectAt(sCrlDataObjectCount++)));
     }
 
     /**
      * Generates a certificate object and initializes it with the data
      * read from the input stream inStream.
      */
-    public Certificate engineGenerateCertificate(
-        InputStream in) 
+    public java.security.cert.Certificate engineGenerateCertificate(
+        InputStream in)
         throws CertificateException
     {
         if (currentStream == null)
@@ -197,8 +198,6 @@
                 }
             }
 
-            int limit = ProviderUtil.getReadLimit(in);
-
             PushbackInputStream pis = new PushbackInputStream(in);
             int tag = pis.read();
 
@@ -215,12 +214,12 @@
             }
             else
             {
-                return readDERCertificate(new ASN1InputStream(pis, limit));
+                return readDERCertificate(new ASN1InputStream(pis));
             }
         }
         catch (Exception e)
         {
-            throw new CertificateException(e);
+            throw new ExCertificateException(e);
         }
     }
 
@@ -229,11 +228,11 @@
      * read from the given input stream inStream.
      */
     public Collection engineGenerateCertificates(
-        InputStream inStream) 
+        InputStream inStream)
         throws CertificateException
     {
-        Certificate     cert;
-        List            certs = new ArrayList();
+        java.security.cert.Certificate     cert;
+        List certs = new ArrayList();
 
         while ((cert = engineGenerateCertificate(inStream)) != null)
         {
@@ -248,7 +247,7 @@
      * it with the data read from the input stream inStream.
      */
     public CRL engineGenerateCRL(
-        InputStream inStream) 
+        InputStream inStream)
         throws CRLException
     {
         if (currentCrlStream == null)
@@ -280,8 +279,6 @@
                 }
             }
 
-            int limit = ProviderUtil.getReadLimit(inStream);
-
             PushbackInputStream pis = new PushbackInputStream(inStream);
             int tag = pis.read();
 
@@ -298,7 +295,7 @@
             }
             else
             {       // lazy evaluate to help processing of large CRLs
-                return readDERCRL(new ASN1InputStream(pis, limit, true));
+                return readDERCRL(new ASN1InputStream(pis, true));
             }
         }
         catch (CRLException e)
@@ -321,11 +318,11 @@
      * and the contents are ignored.
      */
     public Collection engineGenerateCRLs(
-        InputStream inStream) 
+        InputStream inStream)
         throws CRLException
     {
-        CRL     crl;
-        List    crls = new ArrayList();
+        CRL crl;
+        List crls = new ArrayList();
 
         while ((crl = engineGenerateCRL(inStream)) != null)
         {
@@ -337,7 +334,7 @@
 
     public Iterator engineGetCertPathEncodings()
     {
-        return PKIXCertPath.certPathEncodings.iterator();
+        return null; // TODO: PKIXCertPath.certPathEncodings.iterator();
     }
 
     public CertPath engineGenerateCertPath(
@@ -374,4 +371,27 @@
         }
         return new PKIXCertPath(certificates);
     }
+
+    private class ExCertificateException
+        extends CertificateException
+    {
+        private Throwable cause;
+
+        public ExCertificateException(Throwable cause)
+        {
+            this.cause = cause;
+        }
+
+        public ExCertificateException(String msg, Throwable cause)
+        {
+            super(msg);
+
+            this.cause = cause;
+        }
+
+        public Throwable getCause()
+        {
+            return cause;
+        }
+    }
 }
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
new file mode 100644
index 0000000..a4c701d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class KeyFactory
+    extends KeyFactorySpi
+{
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                PrivateKeyInfo info = PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                PrivateKey     key = BouncyCastleProvider.getPrivateKey(info);
+
+                if (key != null)
+                {
+                    return key;
+                }
+
+                throw new InvalidKeySpecException("no factory found for OID: " + info.getPrivateKeyAlgorithm().getAlgorithm());
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException(e.toString());
+            }
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof X509EncodedKeySpec)
+        {
+            try
+            {
+                SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded());
+                PublicKey            key = BouncyCastleProvider.getPublicKey(info);
+
+                if (key != null)
+                {
+                    return key;
+                }
+
+                throw new InvalidKeySpecException("no factory found for OID: " + info.getAlgorithm().getAlgorithm());
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException(e.toString());
+            }
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+        {
+            return new PKCS8EncodedKeySpec(key.getEncoded());
+        }
+        else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+        {
+            return new X509EncodedKeySpec(key.getEncoded());
+        }
+
+        throw new InvalidKeySpecException("not implemented yet " + key + " " + keySpec);
+    }
+
+    protected Key engineTranslateKey(Key key)
+        throws InvalidKeyException
+    {
+        throw new InvalidKeyException("not implemented yet " + key);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
new file mode 100644
index 0000000..8699c3c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
@@ -0,0 +1,93 @@
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.util.encoders.Base64;
+
+public class PEMUtil
+{
+    private final String _header1;
+    private final String _header2;
+    private final String _footer1;
+    private final String _footer2;
+
+    PEMUtil(
+        String type)
+    {
+        _header1 = "-----BEGIN " + type + "-----";
+        _header2 = "-----BEGIN X509 " + type + "-----";
+        _footer1 = "-----END " + type + "-----";
+        _footer2 = "-----END X509 " + type + "-----";
+    }
+
+    private String readLine(
+        InputStream in)
+        throws IOException
+    {
+        int             c;
+        StringBuffer l = new StringBuffer();
+
+        do
+        {
+            while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+            {
+                if (c == '\r')
+                {
+                    continue;
+                }
+
+                l.append((char)c);
+            }
+        }
+        while (c >= 0 && l.length() == 0);
+
+        if (c < 0)
+        {
+            return null;
+        }
+
+        return l.toString();
+    }
+
+    ASN1Sequence readPEMObject(
+        InputStream in)
+        throws IOException
+    {
+        String line;
+        StringBuffer pemBuf = new StringBuffer();
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.startsWith(_header1) || line.startsWith(_header2))
+            {
+                break;
+            }
+        }
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.startsWith(_footer1) || line.startsWith(_footer2))
+            {
+                break;
+            }
+
+            pemBuf.append(line);
+        }
+
+        if (pemBuf.length() != 0)
+        {
+            try
+            {
+                return ASN1Sequence.getInstance(Base64.decode(pemBuf.toString()));
+            }
+            catch (Exception e)
+            {
+                throw new IOException("malformed PEM data encountered");
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
similarity index 86%
rename from src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
rename to src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
index af4b8ab..e13412d 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
@@ -24,17 +24,20 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
 import org.bouncycastle.asn1.pkcs.ContentInfo;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.SignedData;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.io.pem.PemObject;
 // BEGIN android-removed
-// import org.bouncycastle.openssl.PEMWriter;
+// import org.bouncycastle.util.io.pem.PemWriter;
 // END android-removed
 
 /**
@@ -68,7 +71,7 @@
             return certs;
         }
         
-        X500Principal   issuer = ((X509Certificate)certs.get(0)).getIssuerX500Principal();
+        X500Principal issuer = ((X509Certificate)certs.get(0)).getIssuerX500Principal();
         boolean         okay = true;
         
         for (int i = 1; i != certs.size(); i++) 
@@ -92,15 +95,15 @@
         }
         
         // find end-entity cert
-        List       retList = new ArrayList(certs.size());
-        List       orig = new ArrayList(certs);
+        List retList = new ArrayList(certs.size());
+        List orig = new ArrayList(certs);
 
         for (int i = 0; i < certs.size(); i++)
         {
             X509Certificate cert = (X509Certificate)certs.get(i);
             boolean         found = false;
             
-            X500Principal   subject = cert.getSubjectX500Principal();
+            X500Principal subject = cert.getSubjectX500Principal();
             
             for (int j = 0; j != certs.size(); j++)
             {
@@ -172,7 +175,7 @@
             if (encoding.equalsIgnoreCase("PkiPath"))
             {
                 ASN1InputStream derInStream = new ASN1InputStream(inStream);
-                DERObject derObject = derInStream.readObject();
+                ASN1Primitive derObject = derInStream.readObject();
                 if (!(derObject instanceof ASN1Sequence))
                 {
                     throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
@@ -183,7 +186,7 @@
                 while (e.hasMoreElements())
                 {
                     ASN1Encodable element = (ASN1Encodable)e.nextElement();
-                    byte[] encoded = element.getEncoded(ASN1Encodable.DER);
+                    byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
                     certificates.add(0, certFactory.generateCertificate(
                         new ByteArrayInputStream(encoded)));
                 }
@@ -204,13 +207,13 @@
                 throw new CertificateException("unsupported encoding: " + encoding);
             }
         }
-        catch (IOException ex) 
+        catch (IOException ex)
         {
-            throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString()); 
+            throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
         }
-        catch (NoSuchProviderException ex) 
+        catch (NoSuchProviderException ex)
         {
-            throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString()); 
+            throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
         }
         
         this.certificates = sortCerts(certificates);
@@ -234,7 +237,7 @@
      * the default encoding.
      *
      * @return the encoded bytes
-     * @exception CertificateEncodingException if an encoding error occurs
+     * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
      **/
     public byte[] getEncoded()
         throws CertificateEncodingException
@@ -257,7 +260,7 @@
      *
      * @param encoding the name of the encoding to use
      * @return the encoded bytes
-     * @exception CertificateEncodingException if an encoding error
+     * @exception java.security.cert.CertificateEncodingException if an encoding error
      * occurs or the encoding requested is not supported
      *
      **/
@@ -286,11 +289,11 @@
                 v.add(toASN1Object((X509Certificate)certificates.get(i)));
             }
             
-            SignedData  sd = new SignedData(
-                                     new DERInteger(1),
+            SignedData sd = new SignedData(
+                                     new ASN1Integer(1),
                                      new DERSet(),
                                      encInfo, 
-                                     new DERSet(v), 
+                                     new DERSet(v),
                                      null, 
                                      new DERSet());
 
@@ -301,15 +304,15 @@
         // else if (encoding.equalsIgnoreCase("PEM"))
         // {
         //     ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-        //     PEMWriter             pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+        //     PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
         //
         //     try
         //     {
         //         for (int i = 0; i != certificates.size(); i++)
         //         {
-        //             pWrt.writeObject(certificates.get(i));
+        //             pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
         //         }
-        //     
+        //
         //         pWrt.close();
         //     }
         //     catch (Exception e)
@@ -344,7 +347,7 @@
      *
      * @return the DERObject
      **/
-    private DERObject toASN1Object(
+    private ASN1Primitive toASN1Object(
         X509Certificate cert)
         throws CertificateEncodingException
     {
@@ -358,12 +361,12 @@
         }
     }
     
-    private byte[] toDEREncoded(ASN1Encodable obj) 
+    private byte[] toDEREncoded(ASN1Encodable obj)
         throws CertificateEncodingException
     {
         try
         {
-            return obj.getEncoded(ASN1Encodable.DER);
+            return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
new file mode 100644
index 0000000..692b0d7
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.jcajce.provider.config;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * Implemented by the BC provider. This allows setting of hidden parameters,
+ * such as the ImplicitCA parameters from X.962, if used.
+ */
+public interface ConfigurableProvider
+{
+    /**
+     * Elliptic Curve CA parameters - thread local version
+     */
+    static final String      THREAD_LOCAL_EC_IMPLICITLY_CA = "threadLocalEcImplicitlyCa";
+
+    /**
+     * Elliptic Curve CA parameters - thread local version
+     */
+    static final String      EC_IMPLICITLY_CA = "ecImplicitlyCa";
+
+    /**
+     * Diffie-Hellman Default Parameters - thread local version
+     */
+    static final String      THREAD_LOCAL_DH_DEFAULT_PARAMS = "threadLocalDhDefaultParams";
+
+    /**
+     * Diffie-Hellman Default Parameters - VM wide version
+     */
+    static final String      DH_DEFAULT_PARAMS = "DhDefaultParams";
+
+    void setParameter(String parameterName, Object parameter);
+
+    void addAlgorithm(String key, String value);
+
+    boolean hasAlgorithm(String type, String name);
+
+    void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter);
+
+    AsymmetricKeyInfoConverter getConverter(ASN1ObjectIdentifier oid);
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java b/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
new file mode 100644
index 0000000..2b7efe9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.jcajce.provider.config;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+public interface ProviderConfiguration
+{
+    ECParameterSpec getEcImplicitlyCa();
+
+    DHParameterSpec getDHDefaultParameters();
+}
diff --git a/src/main/java/org/bouncycastle/jce/ProviderConfigurationPermission.java b/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
similarity index 84%
rename from src/main/java/org/bouncycastle/jce/ProviderConfigurationPermission.java
rename to src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
index dba4db0..b21afc5 100644
--- a/src/main/java/org/bouncycastle/jce/ProviderConfigurationPermission.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
@@ -1,11 +1,11 @@
-package org.bouncycastle.jce;
-
-import org.bouncycastle.util.Strings;
+package org.bouncycastle.jcajce.provider.config;
 
 import java.security.BasicPermission;
 import java.security.Permission;
 import java.util.StringTokenizer;
 
+import org.bouncycastle.util.Strings;
+
 /**
  * A permission class to define what can be done with the ConfigurableProvider interface.
  * <p>
@@ -28,12 +28,17 @@
     extends BasicPermission
 {
     private static final int  THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01;
-
     private static final int  EC_IMPLICITLY_CA = 0x02;
-    private static final int  ALL = THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA;
+    private static final int  THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04;
+    private static final int  DH_DEFAULT_PARAMS = 0x08;
+
+    private static final int  ALL = THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS;
 
     private static final String THREAD_LOCAL_EC_IMPLICITLY_CA_STR = "threadlocalecimplicitlyca";
     private static final String EC_IMPLICITLY_CA_STR = "ecimplicitlyca";
+    private static final String THREAD_LOCAL_DH_DEFAULT_PARAMS_STR = "threadlocaldhdefaultparams";
+    private static final String DH_DEFAULT_PARAMS_STR = "dhdefaultparams";
+
     private static final String ALL_STR = "all";
 
     private final String actions;
@@ -71,6 +76,14 @@
             {
                 mask |= EC_IMPLICITLY_CA;
             }
+            else if (s.equals(THREAD_LOCAL_DH_DEFAULT_PARAMS_STR))
+            {
+                mask |= THREAD_LOCAL_DH_DEFAULT_PARAMS;
+            }
+            else if (s.equals(DH_DEFAULT_PARAMS_STR))
+            {
+                mask |= DH_DEFAULT_PARAMS;
+            }
             else if (s.equals(ALL_STR))
             {
                 mask |= ALL;
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java
new file mode 100644
index 0000000..3c5b78d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import java.security.MessageDigest;
+
+import org.bouncycastle.crypto.Digest;
+
+public class BCMessageDigest
+    extends MessageDigest
+{
+    protected Digest  digest;
+
+    protected BCMessageDigest(
+        Digest digest)
+    {
+        super(digest.getAlgorithmName());
+
+        this.digest = digest;
+    }
+
+    public void engineReset() 
+    {
+        digest.reset();
+    }
+
+    public void engineUpdate(
+        byte    input) 
+    {
+        digest.update(input);
+    }
+
+    public void engineUpdate(
+        byte[]  input,
+        int     offset,
+        int     len) 
+    {
+        digest.update(input, offset, len);
+    }
+
+    public byte[] engineDigest() 
+    {
+        byte[]  digestBytes = new byte[digest.getDigestSize()];
+
+        digest.doFinal(digestBytes, 0);
+
+        return digestBytes;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
new file mode 100644
index 0000000..2325f59
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class DigestAlgorithmProvider
+    extends AlgorithmProvider
+{
+    protected void addHMACAlgorithm(
+        ConfigurableProvider provider,
+        String algorithm,
+        String algorithmClassName,
+        String keyGeneratorClassName)
+    {
+        String mainName = "HMAC" + algorithm;
+
+        provider.addAlgorithm("Mac." + mainName, algorithmClassName);
+        provider.addAlgorithm("Alg.Alias.Mac.HMAC-" + algorithm, mainName);
+        provider.addAlgorithm("Alg.Alias.Mac.HMAC/" + algorithm, mainName);
+        provider.addAlgorithm("KeyGenerator." + mainName, keyGeneratorClassName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC-" + algorithm, mainName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC/" + algorithm, mainName);
+    }
+
+    protected void addHMACAlias(
+        ConfigurableProvider provider,
+        String algorithm,
+        ASN1ObjectIdentifier oid)
+    {
+        String mainName = "HMAC" + algorithm;
+
+        provider.addAlgorithm("Alg.Alias.Mac." + oid, mainName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid, mainName);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
new file mode 100644
index 0000000..6834e3c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class MD5
+{
+    /**
+     * MD5 HMac
+     */
+    public static class HashMac
+        extends JCEMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new MD5Digest()));
+        }
+    }
+
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACMD5", 128, new CipherKeyGenerator());
+        }
+    }
+
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new MD5Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new MD5Digest((MD5Digest)digest);
+
+            return d;
+        }
+    }
+
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = MD5.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("MessageDigest.MD5", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
+
+            addHMACAlgorithm(provider, "MD5", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "MD5", IANAObjectIdentifiers.hmacMD5);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
new file mode 100644
index 0000000..2a9eceb
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA1
+{
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA1Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA1Digest((SHA1Digest)digest);
+
+            return d;
+        }
+    }
+
+    /**
+     * SHA1 HMac
+     */
+    public static class HashMac
+        extends JCEMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA1Digest()));
+        }
+    }
+
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA1", 160, new CipherKeyGenerator());
+        }
+    }
+
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA1.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("MessageDigest.SHA-1", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA", "SHA-1");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
+
+            addHMACAlgorithm(provider, "SHA1", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
+            addHMACAlias(provider, "SHA1", IANAObjectIdentifiers.hmacSHA1);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
new file mode 100644
index 0000000..4e25c39
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -0,0 +1,73 @@
+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.SHA256Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA256
+{
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA256Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA256Digest((SHA256Digest)digest);
+
+            return d;
+        }
+    }
+
+    public static class HashMac
+        extends JCEMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA256Digest()));
+        }
+    }
+
+        /**
+     * HMACSHA256
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA256", 256, new CipherKeyGenerator());
+        }
+    }
+
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA256.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("MessageDigest.SHA-256", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
+
+            addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
new file mode 100644
index 0000000..c724310
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -0,0 +1,73 @@
+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.SHA384Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA384
+{
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA384Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA384Digest((SHA384Digest)digest);
+
+            return d;
+        }
+    }
+
+    public static class HashMac
+        extends JCEMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA384Digest()));
+        }
+    }
+
+    /**
+     * HMACSHA384
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA384", 384, new CipherKeyGenerator());
+        }
+    }
+
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA384.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("MessageDigest.SHA-384", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
+
+            addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
new file mode 100644
index 0000000..cae9e7b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -0,0 +1,74 @@
+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.SHA512Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA512
+{
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA512Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA512Digest((SHA512Digest)digest);
+
+            return d;
+        }
+    }
+
+    public static class HashMac
+        extends JCEMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA512Digest()));
+        }
+    }
+
+    /**
+     * HMACSHA512
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA512", 512, new CipherKeyGenerator());
+        }
+    }
+
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA512.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("MessageDigest.SHA-512", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
+
+            addHMACAlgorithm(provider, "SHA512", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
+        }
+    }
+
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
new file mode 100644
index 0000000..1e12ee3
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -0,0 +1,295 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+// BEGIN android-removed
+// import java.security.AlgorithmParameters;
+// import java.security.InvalidAlgorithmParameterException;
+// END android-removed
+import java.security.SecureRandom;
+// BEGIN android-removed
+// import java.security.spec.AlgorithmParameterSpec;
+//
+// import javax.crypto.spec.IvParameterSpec;
+// END android-removed
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.AESWrapEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+// END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+// BEGIN android-removed
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+// END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jce.provider.BouncyCastleProvider;
+// END android-removed
+
+public final class AES
+{
+    private AES()
+    {
+    }
+    
+    public static class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new AESFastEngine());
+        }
+    }
+
+    public static class CBC
+       extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new AESFastEngine()), 128);
+        }
+    }
+
+    static public class CFB
+        extends BaseBlockCipher
+    {
+        public CFB()
+        {
+            super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
+        }
+    }
+
+    static public class OFB
+        extends BaseBlockCipher
+    {
+        public OFB()
+        {
+            super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class AESCMAC
+    //     extends BaseMac
+    // {
+    //     public AESCMAC()
+    //     {
+    //         super(new CMac(new AESFastEngine()));
+    //     }
+    // }
+    // END android-removed
+    
+    static public class Wrap
+        extends BaseWrapCipher
+    {
+        public Wrap()
+        {
+            super(new AESWrapEngine());
+        }
+    }
+    
+    // BEGIN android-removed
+    // public static class RFC3211Wrap
+    //     extends BaseWrapCipher
+    // {
+    //     public RFC3211Wrap()
+    //     {
+    //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
+    //     }
+    // }
+    // END android-removed
+
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            this(192);
+        }
+
+        public KeyGen(int keySize)
+        {
+            super("AES", keySize, new CipherKeyGenerator());
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class KeyGen128
+    //     extends KeyGen
+    // {
+    //     public KeyGen128()
+    //     {
+    //         super(128);
+    //     }
+    // }
+    //
+    // public static class KeyGen192
+    //     extends KeyGen
+    // {
+    //     public KeyGen192()
+    //     {
+    //         super(192);
+    //     }
+    // }
+    //
+    // public static class KeyGen256
+    //     extends KeyGen
+    // {
+    //     public KeyGen256()
+    //     {
+    //         super(256);
+    //     }
+    // }
+    //
+    // public static class AlgParamGen
+    //     extends BaseAlgorithmParameterGenerator
+    // {
+    //     protected void engineInit(
+    //         AlgorithmParameterSpec genParamSpec,
+    //         SecureRandom random)
+    //         throws InvalidAlgorithmParameterException
+    //     {
+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+    //     }
+    //
+    //     protected AlgorithmParameters engineGenerateParameters()
+    //     {
+    //         byte[]  iv = new byte[16];
+    //
+    //         if (random == null)
+    //         {
+    //             random = new SecureRandom();
+    //         }
+    //
+    //         random.nextBytes(iv);
+    //
+    //         AlgorithmParameters params;
+    //
+    //         try
+    //         {
+    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
+    //             params.init(new IvParameterSpec(iv));
+    //         }
+    //         catch (Exception e)
+    //         {
+    //             throw new RuntimeException(e.getMessage());
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    // END android-removed
+
+    public static class AlgParams
+        extends IvAlgorithmParameters
+    {
+        protected String engineToString()
+        {
+            return "AES IV";
+        }
+    }
+
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = AES.class.getName();
+        
+        /**
+         * These three got introduced in some messages as a result of a typo in an
+         * early document. We don't produce anything using these OID values, but we'll
+         * read them.
+         */
+        private static final String wrongAES128 = "2.16.840.1.101.3.4.2";
+        private static final String wrongAES192 = "2.16.840.1.101.3.4.22";
+        private static final String wrongAES256 = "2.16.840.1.101.3.4.42";
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("AlgorithmParameters.AES", PREFIX + "$AlgParams");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+            // BEGIN android-removed
+            // provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+            // END android-removed
+
+            provider.addAlgorithm("Cipher.AES", PREFIX + "$ECB");
+            provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES128, "AES");
+            provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES192, "AES");
+            provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES256, "AES");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
+            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
+            // END android-removed
+            provider.addAlgorithm("Cipher.AESWRAP", PREFIX + "$Wrap");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
+            // END android-removed
+
+            provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
+            // BEGIN android-removed
+            // provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
+            // provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
+            // provider.addAlgorithm("KeyGenerator." + wrongAES256, PREFIX + "$KeyGen256");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
+            // provider.addAlgorithm("KeyGenerator.AESWRAP", PREFIX + "$KeyGen");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
+            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
+            //
+            // provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
+            // END android-removed
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
new file mode 100644
index 0000000..1bbdae7
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.RC4Engine;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class ARC4
+{
+    private ARC4()
+    {
+    }
+    
+    public static class Base
+        extends BaseStreamCipher
+    {
+        public Base()
+        {
+            super(new RC4Engine(), 0);
+        }
+    }
+
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            // BEGIN android-changed
+            super("ARC4", 128, new CipherKeyGenerator());
+            // END android-changed
+        }
+    }
+
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = ARC4.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+
+            provider.addAlgorithm("Cipher.ARC4", PREFIX + "$Base");
+            provider.addAlgorithm("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
+            provider.addAlgorithm("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+            provider.addAlgorithm("Alg.Alias.Cipher.RC4", "ARC4");
+            provider.addAlgorithm("KeyGenerator.ARC4", PREFIX + "$KeyGen");
+            provider.addAlgorithm("Alg.Alias.KeyGenerator.RC4", "ARC4");
+            provider.addAlgorithm("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
+
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
new file mode 100644
index 0000000..0e37487
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.BlowfishEngine;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Blowfish
+{
+    private Blowfish()
+    {
+    }
+    
+    public static class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new BlowfishEngine());
+        }
+    }
+
+    public static class CBC
+        extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new BlowfishEngine()), 64);
+        }
+    }
+
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            super("Blowfish", 128, new CipherKeyGenerator());
+        }
+    }
+
+    public static class AlgParams
+        extends IvAlgorithmParameters
+    {
+        protected String engineToString()
+        {
+            return "Blowfish IV";
+        }
+    }
+
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = Blowfish.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+
+            provider.addAlgorithm("Cipher.BLOWFISH", PREFIX + "$ECB");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher.1.3.6.1.4.1.3029.1.2", PREFIX + "$CBC");
+            // END android-removed
+            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");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
new file mode 100644
index 0000000..3ba874c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
@@ -0,0 +1,316 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.engines.DESEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.generators.DESKeyGenerator;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public final class DES
+{
+    private DES()
+    {
+    }
+
+    static public class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new DESEngine());
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class CBC
+    //     extends BaseBlockCipher
+    // {
+    //     public CBC()
+    //     {
+    //         super(new CBCBlockCipher(new DESEngine()), 64);
+    //     }
+    // }
+    //
+    // /**
+    //  * DES   CFB8
+    //  */
+    // public static class DESCFB8
+    //     extends BaseMac
+    // {
+    //     public DESCFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new DESEngine()));
+    //     }
+    // }
+    //
+    // /**
+    //  * DES64
+    //  */
+    // public static class DES64
+    //     extends BaseMac
+    // {
+    //     public DES64()
+    //     {
+    //         super(new CBCBlockCipherMac(new DESEngine(), 64));
+    //     }
+    // }
+    //
+    // /**
+    //  * DES64with7816-4Padding
+    //  */
+    // public static class DES64with7816d4
+    //     extends BaseMac
+    // {
+    //     public DES64with7816d4()
+    //     {
+    //         super(new CBCBlockCipherMac(new DESEngine(), 64, new ISO7816d4Padding()));
+    //     }
+    // }
+    //
+    // public static class CBCMAC
+    //     extends BaseMac
+    // {
+    //     public CBCMAC()
+    //     {
+    //         super(new CBCBlockCipherMac(new DESEngine()));
+    //     }
+    // }
+    //
+    // static public class CMAC
+    //     extends BaseMac
+    // {
+    //     public CMAC()
+    //     {
+    //         super(new CMac(new DESEngine()));
+    //     }
+    // }
+    //
+    // public static class RFC3211
+    //     extends BaseWrapCipher
+    // {
+    //     public RFC3211()
+    //     {
+    //         super(new RFC3211WrapEngine(new DESEngine()), 8);
+    //     }
+    // }
+    //
+    // public static class AlgParamGen
+    //     extends BaseAlgorithmParameterGenerator
+    // {
+    //     protected void engineInit(
+    //         AlgorithmParameterSpec genParamSpec,
+    //         SecureRandom            random)
+    //         throws InvalidAlgorithmParameterException
+    //     {
+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+    //     }
+    //
+    //     protected AlgorithmParameters engineGenerateParameters()
+    //     {
+    //         byte[]  iv = new byte[8];
+    //
+    //         if (random == null)
+    //         {
+    //             random = new SecureRandom();
+    //         }
+    //
+    //         random.nextBytes(iv);
+    //
+    //         AlgorithmParameters params;
+    //
+    //         try
+    //         {
+    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+    //             params.init(new IvParameterSpec(iv));
+    //         }
+    //         catch (Exception e)
+    //         {
+    //             throw new RuntimeException(e.getMessage());
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    // END android-removed
+
+  /**
+     * DES - the default for this is to generate a key in
+     * a-b-a format that's 24 bytes long but has 16 bytes of
+     * key material (the first 8 bytes is repeated as the last
+     * 8 bytes). If you give it a size, you'll get just what you
+     * asked for.
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("DES", 64, new DESKeyGenerator());
+        }
+
+        protected void engineInit(
+            int             keySize,
+            SecureRandom random)
+        {
+            super.engineInit(keySize, random);
+        }
+
+        protected SecretKey engineGenerateKey()
+        {
+            if (uninitialised)
+            {
+                engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+                uninitialised = false;
+            }
+
+            return new SecretKeySpec(engine.generateKey(), algName);
+        }
+    }
+
+    static public class KeyFactory
+        extends BaseSecretKeyFactory
+    {
+        public KeyFactory()
+        {
+            super("DES", null);
+        }
+
+        protected KeySpec engineGetKeySpec(
+            SecretKey key,
+            Class keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec == null)
+            {
+                throw new InvalidKeySpecException("keySpec parameter is null");
+            }
+            if (key == null)
+            {
+                throw new InvalidKeySpecException("key parameter is null");
+            }
+
+            if (SecretKeySpec.class.isAssignableFrom(keySpec))
+            {
+                return new SecretKeySpec(key.getEncoded(), algName);
+            }
+            else if (DESKeySpec.class.isAssignableFrom(keySpec))
+            {
+                byte[]  bytes = key.getEncoded();
+
+                try
+                {
+                    return new DESKeySpec(bytes);
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESKeySpec)
+            {
+                DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DES");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = DES.class.getName();
+        private static final String PACKAGE = "org.bouncycastle.jcajce.provider.symmetric"; // JDK 1.2
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+
+            provider.addAlgorithm("Cipher.DES", PREFIX + "$ECB");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher." + OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
+            //
+            // addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
+            //
+            // provider.addAlgorithm("Cipher.DESRFC3211WRAP", PREFIX + "$RFC3211");
+            // END android-removed
+
+            provider.addAlgorithm("KeyGenerator.DES", PREFIX + "$KeyGenerator");
+
+            provider.addAlgorithm("SecretKeyFactory.DES", PREFIX + "$KeyFactory");
+
+            // BEGIN android-removed
+            // provider.addAlgorithm("Mac.DESCMAC", PREFIX + "$CMAC");
+            // provider.addAlgorithm("Mac.DESMAC", PREFIX + "$CBCMAC");
+            // provider.addAlgorithm("Alg.Alias.Mac.DES", "DESMAC");
+            //
+            // provider.addAlgorithm("Mac.DESMAC/CFB8", PREFIX + "$DESCFB8");
+            // provider.addAlgorithm("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
+            //
+            // provider.addAlgorithm("Mac.DESMAC64", PREFIX + "$DES64");
+            // provider.addAlgorithm("Alg.Alias.Mac.DES64", "DESMAC64");
+            //
+            // provider.addAlgorithm("Mac.DESMAC64WITHISO7816-4PADDING", PREFIX + "$DES64with7816d4");
+            // provider.addAlgorithm("Alg.Alias.Mac.DES64WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1MACWITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+            // END android-removed
+
+            provider.addAlgorithm("AlgorithmParameters.DES", PACKAGE + ".util.IvAlgorithmParameters");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
+
+            // BEGIN android-removed
+            // provider.addAlgorithm("AlgorithmParameterGenerator.DES",  PREFIX + "$AlgParamGen");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "DES");
+            // END android-removed
+        }
+
+        private void addAlias(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+        {
+            provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid.getId(), name);
+            provider.addAlgorithm("Alg.Alias.KeyFactory." + oid.getId(), name);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
new file mode 100644
index 0000000..8e719d6
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
@@ -0,0 +1,423 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+// BEGIN android-removed
+// import java.security.AlgorithmParameters;
+// import java.security.InvalidAlgorithmParameterException;
+// END android-removed
+import java.security.SecureRandom;
+// BEGIN android-removed
+// import java.security.spec.AlgorithmParameterSpec;
+// END android-removed
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+// BEGIN android-removed
+// import javax.crypto.spec.IvParameterSpec;
+// END android-removed
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+import org.bouncycastle.crypto.engines.DESedeWrapEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+// END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public final class DESede
+{
+    private DESede()
+    {
+    }
+
+    static public class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new DESedeEngine());
+        }
+    }
+
+    static public class CBC
+        extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), 64);
+        }
+    }
+
+    // BEGIN android-removed
+    // /**
+    //  * DESede   CFB8
+    //  */
+    // public static class DESedeCFB8
+    //     extends BaseMac
+    // {
+    //     public DESedeCFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new DESedeEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * DESede64
+     */
+    public static class DESede64
+        extends BaseMac
+    {
+        public DESede64()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64));
+        }
+    }
+
+    /**
+     * DESede64with7816-4Padding
+     */
+    public static class DESede64with7816d4
+        extends BaseMac
+    {
+        public DESede64with7816d4()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
+        }
+    }
+    
+    public static class CBCMAC
+        extends BaseMac
+    {
+        public CBCMAC()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine()));
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class CMAC
+    //     extends BaseMac
+    // {
+    //     public CMAC()
+    //     {
+    //         super(new CMac(new DESedeEngine()));
+    //     }
+    // }
+    // END android-removed
+    
+    public static class Wrap
+        extends BaseWrapCipher
+    {
+        public Wrap()
+        {
+            super(new DESedeWrapEngine());
+        }
+    }
+    
+    // BEGIN android-removed
+    // public static class RFC3211
+    //     extends BaseWrapCipher
+    // {
+    //     public RFC3211()
+    //     {
+    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+    //     }
+    // }
+    // END android-removed
+
+  /**
+     * DESede - the default for this is to generate a key in
+     * a-b-a format that's 24 bytes long but has 16 bytes of
+     * key material (the first 8 bytes is repeated as the last
+     * 8 bytes). If you give it a size, you'll get just what you
+     * asked for.
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        private boolean     keySizeSet = false;
+
+        public KeyGenerator()
+        {
+            super("DESede", 192, new DESedeKeyGenerator());
+        }
+
+        protected void engineInit(
+            int             keySize,
+            SecureRandom random)
+        {
+            super.engineInit(keySize, random);
+            keySizeSet = true;
+        }
+
+        protected SecretKey engineGenerateKey()
+        {
+            if (uninitialised)
+            {
+                engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+                uninitialised = false;
+            }
+
+            //
+            // if no key size has been defined generate a 24 byte key in
+            // the a-b-a format
+            //
+            if (!keySizeSet)
+            {
+                byte[]     k = engine.generateKey();
+
+                System.arraycopy(k, 0, k, 16, 8);
+
+                return new SecretKeySpec(k, algName);
+            }
+            else
+            {
+                return new SecretKeySpec(engine.generateKey(), algName);
+            }
+        }
+    }
+
+    /**
+     * generate a desEDE key in the a-b-c format.
+     */
+    public static class KeyGenerator3
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator3()
+        {
+            super("DESede3", 192, new DESedeKeyGenerator());
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd3-KeyTripleDES-CBC
+     */
+    static public class PBEWithSHAAndDES3Key
+        extends BaseBlockCipher
+    {
+        public PBEWithSHAAndDES3Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()));
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd2-KeyTripleDES-CBC
+     */
+    static public class PBEWithSHAAndDES2Key
+        extends BaseBlockCipher
+    {
+        public PBEWithSHAAndDES2Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()));
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class AlgParamGen
+    //     extends BaseAlgorithmParameterGenerator
+    // {
+    //     protected void engineInit(
+    //         AlgorithmParameterSpec genParamSpec,
+    //         SecureRandom            random)
+    //         throws InvalidAlgorithmParameterException
+    //     {
+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+    //     }
+    //
+    //     protected AlgorithmParameters engineGenerateParameters()
+    //     {
+    //         byte[]  iv = new byte[8];
+    //
+    //         if (random == null)
+    //         {
+    //             random = new SecureRandom();
+    //         }
+    //
+    //         random.nextBytes(iv);
+    //
+    //         AlgorithmParameters params;
+    //
+    //         try
+    //         {
+    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+    //             params.init(new IvParameterSpec(iv));
+    //         }
+    //         catch (Exception e)
+    //         {
+    //             throw new RuntimeException(e.getMessage());
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    // END android-removed
+
+    static public class KeyFactory
+        extends BaseSecretKeyFactory
+    {
+        public KeyFactory()
+        {
+            super("DESede", null);
+        }
+
+        protected KeySpec engineGetKeySpec(
+            SecretKey key,
+            Class keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec == null)
+            {
+                throw new InvalidKeySpecException("keySpec parameter is null");
+            }
+            if (key == null)
+            {
+                throw new InvalidKeySpecException("key parameter is null");
+            }
+
+            if (SecretKeySpec.class.isAssignableFrom(keySpec))
+            {
+                return new SecretKeySpec(key.getEncoded(), algName);
+            }
+            else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+            {
+                byte[]  bytes = key.getEncoded();
+
+                try
+                {
+                    if (bytes.length == 16)
+                    {
+                        byte[]  longKey = new byte[24];
+
+                        System.arraycopy(bytes, 0, longKey, 0, 16);
+                        System.arraycopy(bytes, 0, longKey, 16, 8);
+
+                        return new DESedeKeySpec(longKey);
+                    }
+                    else
+                    {
+                        return new DESedeKeySpec(bytes);
+                    }
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESedeKeySpec)
+            {
+                DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = DESede.class.getName();
+        private static final String PACKAGE = "org.bouncycastle.jcajce.provider.symmetric"; // JDK 1.2
+                
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("Cipher.DESEDE", PREFIX + "$ECB");
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
+            // END android-removed
+            provider.addAlgorithm("Cipher.DESEDEWRAP", PREFIX + "$Wrap");
+            // BEGIN android-changed
+            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
+            // END android-changed
+            // BEGIN android-removed
+            // provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
+            // END android-removed
+
+            if (provider.hasAlgorithm("MessageDigest", "SHA-1"))
+            {
+                provider.addAlgorithm("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3Key");
+                // BEGIN android-removed
+                // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES3Key");
+                // provider.addAlgorithm("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$OldPBEWithSHAAndDES3Key");
+                // END android-removed
+                provider.addAlgorithm("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2Key");
+                // BEGIN android-removed
+                // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES2Key");
+                // END android-removed
+                provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+            }
+
+            provider.addAlgorithm("KeyGenerator.DESEDE", PREFIX + "$KeyGenerator");
+            // BEGIN android-removed
+            // provider.addAlgorithm("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$KeyGenerator3");
+            // provider.addAlgorithm("KeyGenerator.DESEDEWRAP", PREFIX + "$KeyGenerator");
+            // END android-removed
+
+            provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory");
+
+            // BEGIN android-removed
+            // provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
+            // provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+            //
+            // provider.addAlgorithm("Mac.DESEDEMAC/CFB8", PREFIX + "$DESedeCFB8");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+            //
+            // provider.addAlgorithm("Mac.DESEDEMAC64", PREFIX + "$DESede64");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+            //
+            // provider.addAlgorithm("Mac.DESEDEMAC64WITHISO7816-4PADDING", PREFIX + "$DESede64with7816d4");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            // provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            // END android-removed
+
+            provider.addAlgorithm("AlgorithmParameters.DESEDE", PACKAGE + ".util.IvAlgorithmParameters");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+
+            // BEGIN android-removed
+            // provider.addAlgorithm("AlgorithmParameterGenerator.DESEDE",  PREFIX + "$AlgParamGen");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+            // END android-removed
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEPBEKey.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
similarity index 86%
rename from src/main/java/org/bouncycastle/jce/provider/JCEPBEKey.java
rename to src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
index 13b5230..7f5d3c9 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEPBEKey.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.symmetric.util;
 
 import javax.crypto.interfaces.PBEKey;
 import javax.crypto.spec.PBEKeySpec;
@@ -9,7 +9,7 @@
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
 
-public class JCEPBEKey
+public class BCPBEKey
     implements PBEKey
 {
     String              algorithm;
@@ -25,15 +25,15 @@
     /**
      * @param param
      */
-    public JCEPBEKey(
-        String              algorithm,
+    public BCPBEKey(
+        String algorithm,
         DERObjectIdentifier oid,
-        int                 type,
-        int                 digest,
-        int                 keySize,
-        int                 ivSize,
-        PBEKeySpec          pbeKeySpec,
-        CipherParameters    param)
+        int type,
+        int digest,
+        int keySize,
+        int ivSize,
+        PBEKeySpec pbeKeySpec,
+        CipherParameters param)
     {
         this.algorithm = algorithm;
         this.oid = oid;
@@ -100,12 +100,12 @@
         return keySize;
     }
     
-    int getIvSize()
+    public int getIvSize()
     {
         return ivSize;
     }
     
-    CipherParameters getParam()
+    public CipherParameters getParam()
     {
         return param;
     }
@@ -139,7 +139,7 @@
         return oid;
     }
     
-    void setTryWrongPKCS12Zero(boolean tryWrong)
+    public void setTryWrongPKCS12Zero(boolean tryWrong)
     {
         this.tryWrong = tryWrong; 
     }
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
new file mode 100644
index 0000000..63d6548
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.SecureRandom;
+
+public abstract class BaseAlgorithmParameterGenerator
+    extends AlgorithmParameterGeneratorSpi
+{
+    protected SecureRandom  random;
+    protected int           strength = 1024;
+
+    protected void engineInit(
+        int             strength,
+        SecureRandom    random)
+    {
+        this.strength = strength;
+        this.random = random;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
new file mode 100644
index 0000000..8231ad8
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
@@ -0,0 +1,385 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// END android-removed
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
+// END android-removed
+import org.bouncycastle.util.Arrays;
+
+public abstract class BaseAlgorithmParameters
+    extends AlgorithmParametersSpi
+{
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+    protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+        throws InvalidParameterSpecException;
+
+    // BEGIN android-removed
+    // public static class RC2AlgorithmParameters
+    //     extends BaseAlgorithmParameters
+    // {
+    //     private static final short[] table = {
+    //        0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+    //        0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+    //        0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+    //        0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+    //        0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+    //        0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+    //        0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+    //        0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+    //        0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+    //        0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+    //        0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+    //        0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+    //        0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+    //        0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+    //        0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+    //        0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+    //     };
+    //
+    //     private static final short[] ekb = {
+    //        0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+    //        0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+    //        0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+    //        0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+    //        0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+    //        0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+    //        0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+    //        0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+    //        0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+    //        0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+    //        0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+    //        0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+    //        0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+    //        0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+    //        0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+    //        0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+    //     };
+    //
+    //     private byte[]  iv;
+    //     private int     parameterVersion = 58;
+    //
+    //     protected byte[] engineGetEncoded() 
+    //     {
+    //         return Arrays.clone(iv);
+    //     }
+    //
+    //     protected byte[] engineGetEncoded(
+    //         String format) 
+    //         throws IOException
+    //     {
+    //         if (this.isASN1FormatString(format))
+    //         {
+    //             if (parameterVersion == -1)
+    //             {
+    //                 return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+    //             }
+    //             else
+    //             {
+    //                 return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+    //             }
+    //         }
+    //
+    //         if (format.equals("RAW"))
+    //         {
+    //             return engineGetEncoded();
+    //         }
+    //
+    //         return null;
+    //     }
+    //
+    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
+    //         Class paramSpec) 
+    //         throws InvalidParameterSpecException
+    //     {
+    //         if (paramSpec == RC2ParameterSpec.class)
+    //         {
+    //             if (parameterVersion != -1)
+    //             {
+    //                 if (parameterVersion < 256)
+    //                 {
+    //                     return new RC2ParameterSpec(ekb[parameterVersion], iv);
+    //                 }
+    //                 else
+    //                 {
+    //                     return new RC2ParameterSpec(parameterVersion, iv);
+    //                 }
+    //             }
+    //         }
+    //
+    //         if (paramSpec == IvParameterSpec.class)
+    //         {
+    //             return new IvParameterSpec(iv);
+    //         }
+    //
+    //         throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+    //     }
+    //
+    //     protected void engineInit(
+    //         AlgorithmParameterSpec paramSpec) 
+    //         throws InvalidParameterSpecException
+    //     {
+    //         if (paramSpec instanceof IvParameterSpec)
+    //         {
+    //             this.iv = ((IvParameterSpec)paramSpec).getIV();
+    //         }
+    //         else if (paramSpec instanceof RC2ParameterSpec)
+    //         {
+    //             int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+    //             if (effKeyBits != -1)
+    //             {
+    //                 if (effKeyBits < 256)
+    //                 {
+    //                     parameterVersion = table[effKeyBits];
+    //                 }
+    //                 else
+    //                 {
+    //                     parameterVersion = effKeyBits;
+    //                 }
+    //             }
+    //
+    //             this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+    //         }
+    //         else
+    //         {
+    //             throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+    //         }
+    //     }
+    //
+    //     protected void engineInit(
+    //         byte[] params) 
+    //         throws IOException
+    //     {
+    //         this.iv = Arrays.clone(params);
+    //     }
+    //
+    //     protected void engineInit(
+    //         byte[] params,
+    //         String format) 
+    //         throws IOException
+    //     {
+    //         if (this.isASN1FormatString(format))
+    //         {
+    //             RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Primitive.fromByteArray(params));
+    //
+    //             if (p.getRC2ParameterVersion() != null)
+    //             {
+    //                 parameterVersion = p.getRC2ParameterVersion().intValue();
+    //             }
+    //
+    //             iv = p.getIV();
+    //
+    //             return;
+    //         }
+    //
+    //         if (format.equals("RAW"))
+    //         {
+    //             engineInit(params);
+    //             return;
+    //         }
+    //
+    //         throw new IOException("Unknown parameters format in IV parameters object");
+    //     }
+    //
+    //     protected String engineToString() 
+    //     {
+    //         return "RC2 Parameters";
+    //     }
+    // }
+    // END android-removed
+
+    public static class PBKDF2
+        extends BaseAlgorithmParameters
+    {
+        PBKDF2Params params;
+
+        protected byte[] engineGetEncoded()
+        {
+            try
+            {
+                return params.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Oooops! " + e.toString());
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+            String format)
+        {
+            if (this.isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PBEParameterSpec.class)
+            {
+                return new PBEParameterSpec(params.getSalt(),
+                                params.getIterationCount().intValue());
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PBEParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+            }
+
+            PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
+
+            this.params = new PBKDF2Params(pbeSpec.getSalt(),
+                                pbeSpec.getIterationCount());
+        }
+
+        protected void engineInit(
+            byte[] params)
+            throws IOException
+        {
+            this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in PWRIKEK parameters object");
+        }
+
+        protected String engineToString()
+        {
+            return "PBKDF2 Parameters";
+        }
+    }
+
+    public static class PKCS12PBE
+        extends BaseAlgorithmParameters
+    {
+        PKCS12PBEParams params;
+
+        protected byte[] engineGetEncoded() 
+        {
+            try
+            {
+                return params.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Oooops! " + e.toString());
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (this.isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PBEParameterSpec.class)
+            {
+                return new PBEParameterSpec(params.getIV(),
+                                params.getIterations().intValue());
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PBEParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+            }
+
+            PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
+
+            this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+                                pbeSpec.getIterationCount());
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            this.params = PKCS12PBEParams.getInstance(ASN1Primitive.fromByteArray(params));
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "PKCS12 PBE Parameters";
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
new file mode 100644
index 0000000..ce54655
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -0,0 +1,921 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+// END android-removed
+
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.modes.AEADBlockCipher;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CCMBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.CTSBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+// import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.SICBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.paddings.TBCPadding;
+import org.bouncycastle.crypto.paddings.X923Padding;
+import org.bouncycastle.crypto.paddings.ZeroBytePadding;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ParametersWithSBox;
+// END android-removed
+import org.bouncycastle.crypto.params.RC2Parameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.RC5Parameters;
+// 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
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        // BEGIN android-removed
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class,
+                                        // END android-removed
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        // BEGIN android-removed
+                                        // GOST28147ParameterSpec.class
+                                        // END android-removed
+                                    };
+
+    private org.bouncycastle.crypto.BlockCipher baseEngine;
+    private GenericBlockCipher      cipher;
+    private ParametersWithIV        ivParam;
+
+    private int                     ivLength = 0;
+
+    private boolean                 padded;
+
+    private PBEParameterSpec        pbeSpec = null;
+    private String                  pbeAlgorithm = null;
+
+    private String                  modeName = null;
+
+    protected BaseBlockCipher(
+        org.bouncycastle.crypto.BlockCipher engine)
+    {
+        baseEngine = engine;
+
+        cipher = new BufferedGenericBlockCipher(engine);
+    }
+
+    protected BaseBlockCipher(
+        org.bouncycastle.crypto.BlockCipher engine,
+        int ivLength)
+    {
+        baseEngine = engine;
+
+        this.cipher = new BufferedGenericBlockCipher(engine);
+        this.ivLength = ivLength / 8;
+    }
+
+    protected BaseBlockCipher(
+        BufferedBlockCipher engine,
+        int ivLength)
+    {
+        baseEngine = engine.getUnderlyingCipher();
+
+        this.cipher = new BufferedGenericBlockCipher(engine);
+        this.ivLength = ivLength / 8;
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return baseEngine.getBlockSize();
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return cipher.getOutputSize(inputLen);
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        if (engineParams == null)
+        {
+            if (pbeSpec != null)
+            {
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+                    engineParams.init(pbeSpec);
+                }
+                catch (Exception e)
+                {
+                    return null;
+                }
+            }
+            else if (ivParam != null)
+            {
+                String  name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+                if (name.indexOf('/') >= 0)
+                {
+                    name = name.substring(0, name.indexOf('/'));
+                }
+
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+                    engineParams.init(ivParam.getIV());
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        modeName = Strings.toUpperCase(mode);
+
+        if (modeName.equals("ECB"))
+        {
+            ivLength = 0;
+            cipher = new BufferedGenericBlockCipher(baseEngine);
+        }
+        else if (modeName.equals("CBC"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(
+                            new CBCBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("OFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new BufferedGenericBlockCipher(
+                                new OFBBlockCipher(baseEngine, wordSize));
+            }
+            else
+            {
+                cipher = new BufferedGenericBlockCipher(
+                        new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+            }
+        }
+        else if (modeName.startsWith("CFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new BufferedGenericBlockCipher(
+                                new CFBBlockCipher(baseEngine, wordSize));
+            }
+            else
+            {
+                cipher = new BufferedGenericBlockCipher(
+                        new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+            }
+        }
+        // BEGIN android-removed
+        // else if (modeName.startsWith("PGP"))
+        // {
+        //     boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+
+        //     ivLength = baseEngine.getBlockSize();
+        //     cipher = new BufferedGenericBlockCipher(
+        //         new PGPCFBBlockCipher(baseEngine, inlineIV));
+        // }
+        // else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+        // {
+        //     ivLength = 0;
+        //     cipher = new BufferedGenericBlockCipher(
+        //         new OpenPGPCFBBlockCipher(baseEngine));
+        // }
+        // 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();
+            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                        new SICBlockCipher(baseEngine)));
+        }
+        // BEGIN android-removed
+        // else if (modeName.startsWith("GOFB"))
+        // {
+        //     ivLength = baseEngine.getBlockSize();
+        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+        //                 new GOFBBlockCipher(baseEngine)));
+        // }
+        // END android-removed
+        else if (modeName.startsWith("CTS"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+        }
+        else if (modeName.startsWith("CCM"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+        }
+        // BEGIN android-removed
+        // else if (modeName.startsWith("EAX"))
+        // {
+        //     ivLength = baseEngine.getBlockSize();
+        //     cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+        // }
+        // END android-removed
+        else if (modeName.startsWith("GCM"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+        }
+        else
+        {
+            throw new NoSuchAlgorithmException("can't support mode " + mode);
+        }
+    }
+
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        String  paddingName = Strings.toUpperCase(padding);
+
+        if (paddingName.equals("NOPADDING"))
+        {
+            if (cipher.wrapOnNoPadding())
+            {
+                cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+            }
+        }
+        else if (paddingName.equals("WITHCTS"))
+        {
+            cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+        }
+        else
+        {
+            padded = true;
+
+            if (isAEADModeName(modeName))
+            {
+                throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+            }
+            else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+            }
+            else if (paddingName.equals("ZEROBYTEPADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+            }
+            else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+            }
+            else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+            }
+            else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+            }
+            else if (paddingName.equals("TBCPADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+            }
+            else
+            {
+                throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+            }
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        this.pbeSpec = null;
+        this.pbeAlgorithm = null;
+        this.engineParams = null;
+
+        //
+        // basic key check
+        //
+        if (!(key instanceof SecretKey))
+        {
+            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+        }
+
+        //
+        // for RC5-64 we must have some default parameters
+        //
+        if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+        {
+            throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+        }
+
+        //
+        // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+        //
+        if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (k.getOID() != null)
+            {
+                pbeAlgorithm = k.getOID().getId();
+            }
+            else
+            {
+                pbeAlgorithm = k.getAlgorithm();
+            }
+
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                pbeSpec = (PBEParameterSpec)params;
+                param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+
+            if (param instanceof ParametersWithIV)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            if (ivLength != 0)
+            {
+                IvParameterSpec p = (IvParameterSpec)params;
+
+                if (p.getIV().length != ivLength && !isAEADModeName(modeName))
+                {
+                    throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+                }
+
+                if (key instanceof RepeatedSecretKeySpec)
+                {
+                    param = new ParametersWithIV(null, p.getIV());
+                    ivParam = (ParametersWithIV)param;
+                }
+                else
+                {
+                    param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+                    ivParam = (ParametersWithIV)param;
+                }
+            }
+            else
+            {
+                if (modeName != null && modeName.equals("ECB"))
+                {
+                    throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+                }
+                
+                param = new KeyParameter(key.getEncoded());
+            }
+        }
+        // BEGIN android-removed
+        // else if (params instanceof GOST28147ParameterSpec)
+        // {
+        //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
+        //
+        //     param = new ParametersWithSBox(
+        //                new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+        //
+        //     if (gost28147Param.getIV() != null && ivLength != 0)
+        //     {
+        //         param = new ParametersWithIV(param, gost28147Param.getIV());
+        //         ivParam = (ParametersWithIV)param;
+        //     }
+        // }
+        // else if (params instanceof RC2ParameterSpec)
+        // {
+        //     RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
+        //
+        //     param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+        //
+        //     if (rc2Param.getIV() != null && ivLength != 0)
+        //     {
+        //         param = new ParametersWithIV(param, rc2Param.getIV());
+        //         ivParam = (ParametersWithIV)param;
+        //     }
+        // }
+        // else if (params instanceof RC5ParameterSpec)
+        // {
+        //     RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
+        //
+        //     param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+        //     if (baseEngine.getAlgorithmName().startsWith("RC5"))
+        //     {
+        //         if (baseEngine.getAlgorithmName().equals("RC5-32"))
+        //         {
+        //             if (rc5Param.getWordSize() != 32)
+        //             {
+        //                 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+        //             }
+        //         }
+        //         else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+        //         {
+        //             if (rc5Param.getWordSize() != 64)
+        //             {
+        //                 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+        //             }
+        //         }
+        //     }
+        //     else
+        //     {
+        //         throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+        //     }
+        //     if ((rc5Param.getIV() != null) && (ivLength != 0))
+        //     {
+        //         param = new ParametersWithIV(param, rc5Param.getIV());
+        //         ivParam = (ParametersWithIV)param;
+        //     }
+        // }
+        // END android-removed
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        {
+            SecureRandom    ivRandom = random;
+
+            if (ivRandom == null)
+            {
+                ivRandom = new SecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                ivRandom.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+            {
+                throw new InvalidAlgorithmParameterException("no IV set when one expected");
+            }
+        }
+
+        if (random != null && padded)
+        {
+            param = new ParametersWithRandom(param, random);
+        }
+
+        try
+        {
+            switch (opmode)
+            {
+            case Cipher.ENCRYPT_MODE:
+            case Cipher.WRAP_MODE:
+                cipher.init(true, param);
+                break;
+            case Cipher.DECRYPT_MODE:
+            case Cipher.UNWRAP_MODE:
+                cipher.init(false, param);
+                break;
+            default:
+                throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    // try again if possible
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineInit(opmode, key, paramSpec, random);
+        
+        engineParams = params;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        int     length = cipher.getUpdateOutputSize(inputLen);
+
+        if (length > 0)
+        {
+                byte[]  out = new byte[length];
+
+                int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+                if (len == 0)
+                {
+                    return null;
+                }
+                else if (len != out.length)
+                {
+                    byte[]  tmp = new byte[len];
+
+                    System.arraycopy(out, 0, tmp, 0, len);
+
+                    return tmp;
+                }
+
+                return out;
+        }
+
+        cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws ShortBufferException
+    {
+        try
+        {
+            return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+        catch (DataLengthException e)
+        {
+            throw new ShortBufferException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        int     len = 0;
+        byte[]  tmp = new byte[engineGetOutputSize(inputLen)];
+
+        if (inputLen != 0)
+        {
+            len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+        }
+
+        try
+        {
+            len += cipher.doFinal(tmp, len);
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+
+        if (len == tmp.length)
+        {
+            return tmp;
+        }
+
+        byte[]  out = new byte[len];
+
+        System.arraycopy(tmp, 0, out, 0, len);
+
+        return out;
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+    {
+        // BEGIN android-note
+        // added ShortBufferException to the throws statement
+        // END android-note
+        int     len = 0;
+
+        // BEGIN android-added
+        int outputLen = cipher.getOutputSize(inputLen);
+
+        if (outputLen + outputOffset > output.length) {
+            throw new ShortBufferException("need at least " + outputLen + " bytes");
+        }
+        // BEGIN android-added
+        if (inputLen != 0)
+        {
+                len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+
+        try
+        {
+            return (len + cipher.doFinal(output, outputOffset + len));
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+    }
+
+    private boolean isAEADModeName(
+        String modeName)
+    {
+        return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName);
+    }
+
+    /*
+     * The ciphers that inherit from us.
+     */
+
+    static private interface GenericBlockCipher
+    {
+        public void init(boolean forEncryption, CipherParameters params)
+            throws IllegalArgumentException;
+
+        public boolean wrapOnNoPadding();
+
+        public String getAlgorithmName();
+
+        public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher();
+
+        public int getOutputSize(int len);
+
+        public int getUpdateOutputSize(int len);
+
+        public int processByte(byte in, byte[] out, int outOff)
+            throws DataLengthException;
+
+        public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+            throws DataLengthException;
+
+        public int doFinal(byte[] out, int outOff)
+            throws IllegalStateException, InvalidCipherTextException;
+    }
+
+    private static class BufferedGenericBlockCipher
+        implements GenericBlockCipher
+    {
+        private BufferedBlockCipher cipher;
+
+        BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+        {
+            this.cipher = cipher;
+        }
+
+        BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher)
+        {
+            this.cipher = new PaddedBufferedBlockCipher(cipher);
+        }
+
+        BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
+        {
+            this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+        }
+
+        public void init(boolean forEncryption, CipherParameters params)
+            throws IllegalArgumentException
+        {
+            cipher.init(forEncryption, params);
+        }
+
+        public boolean wrapOnNoPadding()
+        {
+            return !(cipher instanceof CTSBlockCipher);
+        }
+
+        public String getAlgorithmName()
+        {
+            return cipher.getUnderlyingCipher().getAlgorithmName();
+        }
+
+        public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
+        {
+            return cipher.getUnderlyingCipher();
+        }
+
+        public int getOutputSize(int len)
+        {
+            return cipher.getOutputSize(len);
+        }
+
+        public int getUpdateOutputSize(int len)
+        {
+            return cipher.getUpdateOutputSize(len);
+        }
+
+        public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processByte(in, out, outOff);
+        }
+
+        public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processBytes(in, inOff, len, out, outOff);
+        }
+
+        public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+        {
+            return cipher.doFinal(out, outOff);
+        }
+    }
+
+    private static class AEADGenericBlockCipher
+        implements GenericBlockCipher
+    {
+        private AEADBlockCipher cipher;
+
+        AEADGenericBlockCipher(AEADBlockCipher cipher)
+        {
+            this.cipher = cipher;
+        }
+
+        public void init(boolean forEncryption, CipherParameters params)
+            throws IllegalArgumentException
+        {
+            cipher.init(forEncryption, params);
+        }
+
+        public String getAlgorithmName()
+        {
+            return cipher.getUnderlyingCipher().getAlgorithmName();
+        }
+
+        public boolean wrapOnNoPadding()
+        {
+            return false;
+        }
+
+        public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
+        {
+            return cipher.getUnderlyingCipher();
+        }
+
+        public int getOutputSize(int len)
+        {
+            return cipher.getOutputSize(len);
+        }
+
+        public int getUpdateOutputSize(int len)
+        {
+            return cipher.getUpdateOutputSize(len);
+        }
+
+        public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processByte(in, out, outOff);
+        }
+
+        public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processBytes(in, inOff, len, out, outOff);
+        }
+
+        public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+        {
+            return cipher.doFinal(out, outOff);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
new file mode 100644
index 0000000..0e190d3
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
@@ -0,0 +1,83 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class BaseKeyGenerator
+    extends KeyGeneratorSpi
+{
+    protected String                algName;
+    protected int                   keySize;
+    protected int                   defaultKeySize;
+    protected CipherKeyGenerator    engine;
+
+    protected boolean               uninitialised = true;
+
+    protected BaseKeyGenerator(
+        String algName,
+        int defaultKeySize,
+        CipherKeyGenerator engine)
+    {
+        this.algName = algName;
+        this.keySize = this.defaultKeySize = defaultKeySize;
+        this.engine = engine;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+    throws InvalidAlgorithmParameterException
+    {
+        throw new InvalidAlgorithmParameterException("Not Implemented");
+    }
+
+    protected void engineInit(
+        SecureRandom    random)
+    {
+        if (random != null)
+        {
+            engine.init(new KeyGenerationParameters(random, defaultKeySize));
+            uninitialised = false;
+        }
+    }
+
+    protected void engineInit(
+        int             keySize,
+        SecureRandom    random)
+    {
+        try
+        {
+            // BEGIN android-added
+            if (random == null) {
+                random = new SecureRandom();
+            }
+            // END android-added
+            engine.init(new KeyGenerationParameters(random, keySize));
+            uninitialised = false;
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new InvalidParameterException(e.getMessage());
+        }
+    }
+
+    protected SecretKey engineGenerateKey()
+    {
+        if (uninitialised)
+        {
+            engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+            uninitialised = false;
+        }
+
+        return new SecretKeySpec(engine.generateKey(), algName);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
new file mode 100644
index 0000000..55c768f
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
@@ -0,0 +1,463 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.MacSpi;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.MD4Digest;
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
+// import org.bouncycastle.crypto.digests.TigerDigest;
+// END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.engines.RC2Engine;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.GOST28147Mac;
+// END android-removed
+import org.bouncycastle.crypto.macs.HMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
+// import org.bouncycastle.crypto.macs.OldHMac;
+// END android-removed
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class BaseMac
+    extends MacSpi implements PBE
+{
+    private Mac macEngine;
+
+    private int                     pbeType = PKCS12;
+    private int                     pbeHash = SHA1;
+    private int                     keySize = 160;
+
+    protected BaseMac(
+        Mac macEngine)
+    {
+        this.macEngine = macEngine;
+    }
+
+    protected BaseMac(
+        Mac macEngine,
+        int pbeType,
+        int pbeHash,
+        int keySize)
+    {
+        this.macEngine = macEngine;
+        this.pbeType = pbeType;
+        this.pbeHash = pbeHash;
+        this.keySize = keySize;
+    }
+
+    protected void engineInit(
+        Key                     key,
+        AlgorithmParameterSpec  params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        if (key == null)
+        {
+            throw new InvalidKeyException("key is null");
+        }
+
+        if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEMacParameters(k, params);
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        macEngine.init(param);
+    }
+
+    protected int engineGetMacLength() 
+    {
+        return macEngine.getMacSize();
+    }
+
+    protected void engineReset() 
+    {
+        macEngine.reset();
+    }
+
+    protected void engineUpdate(
+        byte    input) 
+    {
+        macEngine.update(input);
+    }
+
+    protected void engineUpdate(
+        byte[]  input,
+        int     offset,
+        int     len) 
+    {
+        macEngine.update(input, offset, len);
+    }
+
+    protected byte[] engineDoFinal() 
+    {
+        byte[]  out = new byte[engineGetMacLength()];
+
+        macEngine.doFinal(out, 0);
+
+        return out;
+    }
+
+    /**
+     * the classes that extend directly off us.
+     */
+
+    /**
+     * DES
+     */
+    public static class DES
+        extends BaseMac
+    {
+        public DES()
+        {
+            super(new CBCBlockCipherMac(new DESEngine()));
+        }
+    }
+
+    /**
+     * DES 64 bit MAC
+     */
+    public static class DES64
+        extends BaseMac
+    {
+        public DES64()
+        {
+            super(new CBCBlockCipherMac(new DESEngine(), 64));
+        }
+    }
+
+    /**
+     * RC2
+     */
+    public static class RC2
+        extends BaseMac
+    {
+        public RC2()
+        {
+            super(new CBCBlockCipherMac(new RC2Engine()));
+        }
+    }
+
+    // BEGIN android-removed
+    // /**
+    //  * GOST28147
+    //  */
+    // public static class GOST28147
+    //     extends BaseMac
+    // {
+    //     public GOST28147()
+    //     {
+    //         super(new GOST28147Mac());
+    //     }
+    // }
+    //
+    //
+    //
+    // /**
+    //  * DES
+    //  */
+    // public static class DESCFB8
+    //     extends BaseMac
+    // {
+    //     public DESCFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new DESEngine()));
+    //     }
+    // }
+    //
+    // /**
+    //  * RC2CFB8
+    //  */
+    // public static class RC2CFB8
+    //     extends BaseMac
+    // {
+    //     public RC2CFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new RC2Engine()));
+    //     }
+    // }
+    //
+    // /**
+    //  * DES9797Alg3with7816-4Padding
+    //  */
+    // public static class DES9797Alg3with7816d4
+    //     extends BaseMac
+    // {
+    //     public DES9797Alg3with7816d4()
+    //     {
+    //         super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
+    //     }
+    // }
+    //
+    // /**
+    //  * DES9797Alg3
+    //  */
+    // public static class DES9797Alg3
+    //     extends BaseMac
+    // {
+    //     public DES9797Alg3()
+    //     {
+    //         super(new ISO9797Alg3Mac(new DESEngine()));
+    //     }
+    // }
+    //
+    // /**
+    //  * MD2 HMac
+    //  */
+    // public static class MD2
+    //     extends BaseMac
+    // {
+    //     public MD2()
+    //     {
+    //         super(new HMac(new MD2Digest()));
+    //     }
+    // }
+    //
+    // /**
+    //  * MD4 HMac
+    //  */
+    // public static class MD4
+    //     extends BaseMac
+    // {
+    //     public MD4()
+    //     {
+    //         super(new HMac(new MD4Digest()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * MD5 HMac
+     */
+    public static class MD5
+        extends BaseMac
+    {
+        public MD5()
+        {
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.MD5()));
+            // END android-changed
+        }
+    }
+
+    /**
+     * SHA1 HMac
+     */
+    public static class SHA1
+        extends BaseMac
+    {
+        public SHA1()
+        {
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA1()));
+            // END android-changed
+        }
+    }
+
+    // BEGIN android-removed
+    // /**
+    //  * SHA-224 HMac
+    //  */
+    // public static class SHA224
+    //     extends BaseMac
+    // {
+    //     public SHA224()
+    //     {
+    //         super(new HMac(new SHA224Digest()));
+    //     }
+    // }
+    // END android-removed
+    
+    /**
+     * SHA-256 HMac
+     */
+    public static class SHA256
+        extends BaseMac
+    {
+        public SHA256()
+        {
+            super(new HMac(new OpenSSLDigest.SHA256()));
+        }
+    }
+
+    /**
+     * SHA-384 HMac
+     */
+    public static class SHA384
+        extends BaseMac
+    {
+        public SHA384()
+        {
+            super(new HMac(new OpenSSLDigest.SHA384()));
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class OldSHA384
+    //     extends BaseMac
+    // {
+    //     public OldSHA384()
+    //     {
+    //         super(new OldHMac(new SHA384Digest()));
+    //     }
+    // }
+    // END android-removed
+    
+    /**
+     * SHA-512 HMac
+     */
+    public static class SHA512
+        extends BaseMac
+    {
+        public SHA512()
+        {
+            super(new HMac(new OpenSSLDigest.SHA512()));
+        }
+    }
+
+    // BEGIN android-removed
+    // /**
+    //  * SHA-512 HMac
+    //  */
+    // public static class OldSHA512
+    //     extends BaseMac
+    // {
+    //     public OldSHA512()
+    //     {
+    //         super(new OldHMac(new SHA512Digest()));
+    //     }
+    // }
+    //    
+    // /**
+    //  * RIPEMD128 HMac
+    //  */
+    // public static class RIPEMD128
+    //     extends BaseMac
+    // {
+    //     public RIPEMD128()
+    //     {
+    //         super(new HMac(new RIPEMD128Digest()));
+    //     }
+    // }
+    //
+    // /**
+    //  * RIPEMD160 HMac
+    //  */
+    // public static class RIPEMD160
+    //     extends BaseMac
+    // {
+    //     public RIPEMD160()
+    //     {
+    //         super(new HMac(new RIPEMD160Digest()));
+    //     }
+    // }
+    //
+    // /**
+    //  * Tiger HMac
+    //  */
+    // public static class Tiger
+    //     extends BaseMac
+    // {
+    //     public Tiger()
+    //     {
+    //         super(new HMac(new TigerDigest()));
+    //     }
+    // }
+    //
+    // //
+    // // PKCS12 states that the same algorithm should be used
+    // // for the key generation as is used in the HMAC, so that
+    // // is what we do here.
+    // //
+    //
+    // /**
+    //  * PBEWithHmacRIPEMD160
+    //  */
+    // public static class PBEWithRIPEMD160
+    //     extends BaseMac
+    // {
+    //     public PBEWithRIPEMD160()
+    //     {
+    //         super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * PBEWithHmacSHA
+     */
+    public static class PBEWithSHA
+        extends BaseMac
+    {
+        public PBEWithSHA()
+        {
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA1()), PKCS12, SHA1, 160);
+            // END android-changed
+        }
+    }
+
+    // BEGIN android-removed
+    // /**
+    //  * PBEWithHmacTiger
+    //  */
+    // public static class PBEWithTiger
+    //     extends BaseMac
+    // {
+    //     public PBEWithTiger()
+    //     {
+    //         super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
+    //     }
+    // }
+    // END android-removed
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
new file mode 100644
index 0000000..23e7b19
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
@@ -0,0 +1,196 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Constructor;
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class BaseSecretKeyFactory
+    extends SecretKeyFactorySpi
+    implements PBE
+{
+    protected String                algName;
+    protected DERObjectIdentifier   algOid;
+
+    protected BaseSecretKeyFactory(
+        String algName,
+        DERObjectIdentifier algOid)
+    {
+        this.algName = algName;
+        this.algOid = algOid;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        KeySpec keySpec)
+    throws InvalidKeySpecException
+    {
+        if (keySpec instanceof SecretKeySpec)
+        {
+            return (SecretKey)keySpec;
+        }
+
+        throw new InvalidKeySpecException("Invalid KeySpec");
+    }
+
+    protected KeySpec engineGetKeySpec(
+        SecretKey key,
+        Class keySpec)
+    throws InvalidKeySpecException
+    {
+        if (keySpec == null)
+        {
+            throw new InvalidKeySpecException("keySpec parameter is null");
+        }
+        if (key == null)
+        {
+            throw new InvalidKeySpecException("key parameter is null");
+        }
+        
+        if (SecretKeySpec.class.isAssignableFrom(keySpec))
+        {
+            return new SecretKeySpec(key.getEncoded(), algName);
+        }
+
+        try
+        {
+            Class[] parameters = { byte[].class };
+
+            Constructor c = keySpec.getConstructor(parameters);
+            Object[]    p = new Object[1];
+
+            p[0] = key.getEncoded();
+
+            return (KeySpec)c.newInstance(p);
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeySpecException(e.toString());
+        }
+    }
+
+    protected SecretKey engineTranslateKey(
+        SecretKey key)
+    throws InvalidKeyException
+    {
+        if (key == null)
+        {
+            throw new InvalidKeyException("key parameter is null");
+        }
+        
+        if (!key.getAlgorithm().equalsIgnoreCase(algName))
+        {
+            throw new InvalidKeyException("Key not of type " + algName + ".");
+        }
+
+        return new SecretKeySpec(key.getEncoded(), algName);
+    }
+
+    /*
+     * classes that inherit from us
+     */
+    
+
+
+    static public class DESPBEKeyFactory
+        extends BaseSecretKeyFactory
+    {
+        private boolean forCipher;
+        private int     scheme;
+        private int     digest;
+        private int     keySize;
+        private int     ivSize;
+        
+        public DESPBEKeyFactory(
+            String              algorithm,
+            DERObjectIdentifier oid,
+            boolean             forCipher,
+            int                 scheme,
+            int                 digest,
+            int                 keySize,
+            int                 ivSize)
+        {
+            super(algorithm, oid);
+            
+            this.forCipher = forCipher;
+            this.scheme = scheme;
+            this.digest = digest;
+            this.keySize = keySize;
+            this.ivSize = ivSize;
+        }
+    
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PBEKeySpec)
+            {
+                PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+                CipherParameters    param;
+                
+                if (pbeSpec.getSalt() == null)
+                {
+                    return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+                }
+                
+                if (forCipher)
+                {
+                    param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+                }
+                else
+                {
+                    param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+                }
+
+                KeyParameter kParam;
+                if (param instanceof ParametersWithIV)
+                {
+                    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+                }
+                else
+                {
+                    kParam = (KeyParameter)param;
+                }
+
+                DESParameters.setOddParity(kParam.getKey());
+
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+            }
+            
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+    }
+    
+    static public class DES
+        extends BaseSecretKeyFactory
+    {
+        public DES()
+        {
+            super("DES", null);
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESKeySpec)
+            {
+                DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DES");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
new file mode 100644
index 0000000..2031929
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
@@ -0,0 +1,366 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+// END android-removed
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.StreamBlockCipher;
+import org.bouncycastle.crypto.StreamCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class BaseStreamCipher
+    extends BaseWrapCipher
+    implements PBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        // BEGIN android-removed
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class,
+                                        // END android-removed
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class
+                                    };
+
+    private StreamCipher       cipher;
+    private ParametersWithIV   ivParam;
+
+    private int                     ivLength = 0;
+
+    private PBEParameterSpec        pbeSpec = null;
+    private String                  pbeAlgorithm = null;
+
+    protected BaseStreamCipher(
+        StreamCipher engine,
+        int ivLength)
+    {
+        cipher = engine;
+        this.ivLength = ivLength;
+    }
+
+    protected BaseStreamCipher(
+        BlockCipher engine,
+        int ivLength)
+    {
+        this.ivLength = ivLength;
+
+        cipher = new StreamBlockCipher(engine);
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return inputLen;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        if (engineParams == null)
+        {
+            if (pbeSpec != null)
+            {
+                try
+                {
+                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+                    engineParams.init(pbeSpec);
+
+                    return engineParams;
+                }
+                catch (Exception e)
+                {
+                    return null;
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    /**
+     * should never be called.
+     */
+    protected void engineSetMode(
+        String  mode)
+    {
+        if (!mode.equalsIgnoreCase("ECB"))
+        {
+            throw new IllegalArgumentException("can't support mode " + mode);
+        }
+    }
+
+    /**
+     * should never be called.
+     */
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        if (!padding.equalsIgnoreCase("NoPadding"))
+        {
+            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        this.pbeSpec = null;
+        this.pbeAlgorithm = null;
+
+        this.engineParams = null;
+
+        //
+        // basic key check
+        //
+        if (!(key instanceof SecretKey))
+        {
+            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+        }
+
+        if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (k.getOID() != null)
+            {
+                pbeAlgorithm = k.getOID().getId();
+            }
+            else
+            {
+                pbeAlgorithm = k.getAlgorithm();
+            }
+
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
+                pbeSpec = (PBEParameterSpec)params;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+            
+            if (k.getIvSize() != 0)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+            ivParam = (ParametersWithIV)param;
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        {
+            SecureRandom    ivRandom = random;
+
+            if (ivRandom == null)
+            {
+                ivRandom = new SecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                ivRandom.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("no IV set when one expected");
+            }
+        }
+
+        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:
+            System.out.println("eeek!");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineInit(opmode, key, paramSpec, random);
+        engineParams = params;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        byte[]  out = new byte[inputLen];
+
+        cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+        return out;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws ShortBufferException 
+    {
+        try
+        {
+        cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+
+        return inputLen;
+        }
+        catch (DataLengthException e)
+        {
+            throw new ShortBufferException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        if (inputLen != 0)
+        {
+            byte[] out = engineUpdate(input, inputOffset, inputLen);
+
+            cipher.reset();
+            
+            return out;
+        }
+
+        cipher.reset();
+        
+        return new byte[0];
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+    {
+        if (inputLen != 0)
+        {
+            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+
+        cipher.reset();
+        
+        return inputLen;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
similarity index 80%
rename from src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
rename to src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
index 1a5808b..2800a7f 100644
--- a/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.symmetric.util;
 
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
@@ -28,23 +28,16 @@
 // END android-removed
 import javax.crypto.spec.SecretKeySpec;
 
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.InvalidCipherTextException;
 import org.bouncycastle.crypto.Wrapper;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.RC2WrapEngine;
-// END android-removed
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
-public abstract class WrapCipherSpi extends CipherSpi
+public abstract class BaseWrapCipher
+    extends CipherSpi
     implements PBE
 {
     //
@@ -72,19 +65,19 @@
     private int                       ivSize;
     private byte[]                    iv;
 
-    protected WrapCipherSpi()
+    protected BaseWrapCipher()
     {
     }
 
-    protected WrapCipherSpi(
+    protected BaseWrapCipher(
         Wrapper wrapEngine)
     {
         this(wrapEngine, 0);
     }
 
-    protected WrapCipherSpi(
+    protected BaseWrapCipher(
         Wrapper wrapEngine,
-        int     ivSize)
+        int ivSize)
     {
         this.wrapEngine = wrapEngine;
         this.ivSize = ivSize;
@@ -140,10 +133,10 @@
     {
         CipherParameters        param;
 
-        if (key instanceof JCEPBEKey)
+        if (key instanceof BCPBEKey)
         {
-            JCEPBEKey   k = (JCEPBEKey)key;
-            
+            BCPBEKey k = (BCPBEKey)key;
+
             if (params instanceof PBEParameterSpec)
             {
                 param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
@@ -162,7 +155,7 @@
             param = new KeyParameter(key.getEncoded());
         }
 
-        if (params instanceof javax.crypto.spec.IvParameterSpec)
+        if (params instanceof IvParameterSpec)
         {
             IvParameterSpec iv = (IvParameterSpec) params;
             param = new ParametersWithIV(param, iv.getIV());
@@ -285,7 +278,7 @@
 
     protected byte[] engineWrap(
         Key     key)
-    throws IllegalBlockSizeException, java.security.InvalidKeyException
+    throws IllegalBlockSizeException, InvalidKeyException
     {
         byte[] encoded = key.getEncoded();
         if (encoded == null)
@@ -353,52 +346,28 @@
         else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
         {
             /*
-             * The caller doesnt know the algorithm as it is part of
-             * the encrypted data.
-             */
-            ASN1InputStream bIn = new ASN1InputStream(encoded);
-            PrivateKey      privKey;
-
+                 * The caller doesn't know the algorithm as it is part of
+                 * the encrypted data.
+                 */
             try
             {
-                ASN1Sequence         s = (ASN1Sequence)bIn.readObject();
-                PrivateKeyInfo       in = new PrivateKeyInfo(s);
+                PrivateKeyInfo       in = PrivateKeyInfo.getInstance(encoded);
 
-                DERObjectIdentifier  oid = in.getAlgorithmId().getObjectId();
+                PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
 
-                if (oid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+                if (privKey != null)
                 {
-                    privKey = new JCEECPrivateKey(in);
+                    return privKey;
                 }
-                // BEGIN android-removed
-                // else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
-                // {
-                //     privKey = new JDKGOST3410PrivateKey(in);
-                // }
-                // END android-removed
-                else if (oid.equals(X9ObjectIdentifiers.id_dsa))
+                else
                 {
-                    privKey = new JDKDSAPrivateKey(in);
-                }
-                else if (oid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
-                {
-                    privKey = new JCEDHPrivateKey(in);
-                }
-                else if (oid.equals(X9ObjectIdentifiers.dhpublicnumber))
-                {
-                    privKey = new JCEDHPrivateKey(in);
-                }
-                else    // the old standby!
-                {
-                    privKey = new JCERSAPrivateCrtKey(in);
+                    throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
                 }
             }
             catch (Exception e)
             {
                 throw new InvalidKeyException("Invalid key encoding.");
             }
-
-            return privKey;
         }
         else
         {
@@ -434,18 +403,4 @@
         }
     }
 
-    //
-    // classes that inherit directly from us
-    //
-
-    // BEGIN android-removed
-    // public static class RC2Wrap
-    //     extends WrapCipherSpi
-    // {
-    //     public RC2Wrap()
-    //     {
-    //         super(new RC2WrapEngine());
-    //     }
-    // }
-    // END android-removed
 }
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
new file mode 100644
index 0000000..b5a9552
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
@@ -0,0 +1,118 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.util.Arrays;
+
+public class IvAlgorithmParameters
+    extends BaseAlgorithmParameters
+{
+    private byte[] iv;
+
+    protected byte[] engineGetEncoded()
+        throws IOException
+    {
+        return engineGetEncoded("ASN.1");
+    }
+
+    protected byte[] engineGetEncoded(
+        String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format))
+        {
+            return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+        }
+
+        if (format.equals("RAW"))
+        {
+            return Arrays.clone(iv);
+        }
+
+        return null;
+    }
+
+    protected AlgorithmParameterSpec localEngineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == IvParameterSpec.class)
+        {
+            return new IvParameterSpec(iv);
+        }
+
+        throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (!(paramSpec instanceof IvParameterSpec))
+        {
+            throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+        }
+
+        this.iv = ((IvParameterSpec)paramSpec).getIV();
+    }
+
+    protected void engineInit(
+        byte[] params)
+        throws IOException
+    {
+        //
+        // check that we don't have a DER encoded octet string
+        //
+        if ((params.length % 8) != 0
+            && params[0] == 0x04 && params[1] == params.length - 2)
+        {
+            ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+            params = oct.getOctets();
+        }
+
+        this.iv = Arrays.clone(params);
+    }
+
+    protected void engineInit(
+        byte[] params,
+        String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format))
+        {
+            try
+            {
+                ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+                engineInit(oct.getOctets());
+            }
+            catch (Exception e)
+            {
+                throw new IOException("Exception decoding: " + e);
+            }
+
+            return;
+        }
+
+        if (format.equals("RAW"))
+        {
+            engineInit(params);
+            return;
+        }
+
+        throw new IOException("Unknown parameters format in IV parameters object");
+    }
+
+    protected String engineToString()
+    {
+        return "IV Parameters";
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/PBE.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
similarity index 83%
rename from src/main/java/org/bouncycastle/jce/provider/PBE.java
rename to src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
index e06a27c..cb2cfd7 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PBE.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.symmetric.util;
 
 import java.security.spec.AlgorithmParameterSpec;
 
@@ -9,16 +9,15 @@
 import org.bouncycastle.crypto.PBEParametersGenerator;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.MD2Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.MD5Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD5Digest;
 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.SHA1Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
 // import org.bouncycastle.crypto.digests.TigerDigest;
 // END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
 import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
 import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
@@ -34,10 +33,14 @@
     //
     static final int        MD5         = 0;
     static final int        SHA1        = 1;
-    static final int        RIPEMD160   = 2;
-    static final int        TIGER       = 3;
+    // BEGIN android-removed
+    // static final int        RIPEMD160   = 2;
+    // static final int        TIGER       = 3;
+    // END android-removed
     static final int        SHA256      = 4;
-    static final int        MD2         = 5;
+    // BEGIN android-removed
+    // static final int        MD2         = 5;
+    // END android-removed
 
     static final int        PKCS5S1     = 0;
     static final int        PKCS5S2     = 1;
@@ -65,10 +68,14 @@
                 //     break;
                 // END android-removed
                 case MD5:
-                    generator = new PKCS5S1ParametersGenerator(new MD5Digest());
+                    // BEGIN android-changed
+                    generator = new PKCS5S1ParametersGenerator(new OpenSSLDigest.MD5());
+                    // END android-changed
                     break;
                 case SHA1:
-                    generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
+                    // BEGIN android-changed
+                    generator = new PKCS5S1ParametersGenerator(new OpenSSLDigest.SHA1());
+                    // END android-changed
                     break;
                 default:
                     throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
@@ -88,10 +95,14 @@
                 //     break;
                 // END android-removed
                 case MD5:
-                    generator = new PKCS12ParametersGenerator(new MD5Digest());
+                    // BEGIN android-changed
+                    generator = new PKCS12ParametersGenerator(new OpenSSLDigest.MD5());
+                    // END android-changed
                     break;
                 case SHA1:
-                    generator = new PKCS12ParametersGenerator(new SHA1Digest());
+                    // BEGIN android-changed
+                    generator = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
+                    // END android-changed
                     break;
                 // BEGIN android-removed
                 // case RIPEMD160:
@@ -102,7 +113,9 @@
                 //     break;
                 // END android-removed
                 case SHA256:
-                    generator = new PKCS12ParametersGenerator(new SHA256Digest());
+                    // BEGIN android-changed
+                    generator = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA256());
+                    // END android-changed
                     break;
                 default:
                     throw new IllegalStateException("unknown digest scheme for PBE encryption.");
@@ -120,10 +133,10 @@
          * construct a key and iv (if necessary) suitable for use with a 
          * Cipher.
          */
-        static CipherParameters makePBEParameters(
-            JCEPBEKey               pbeKey,
-            AlgorithmParameterSpec  spec,
-            String                  targetAlgorithm)
+        public static CipherParameters makePBEParameters(
+            BCPBEKey pbeKey,
+            AlgorithmParameterSpec spec,
+            String targetAlgorithm)
         {
             if ((spec == null) || !(spec instanceof PBEParameterSpec))
             {
@@ -180,9 +193,9 @@
          * key size is chosen according the MAC size, or the hashing algorithm,
          * whichever is greater.
          */
-        static CipherParameters makePBEMacParameters(
-            JCEPBEKey               pbeKey,
-            AlgorithmParameterSpec  spec)
+        public static CipherParameters makePBEMacParameters(
+            BCPBEKey pbeKey,
+            AlgorithmParameterSpec spec)
         {
             if ((spec == null) || !(spec instanceof PBEParameterSpec))
             {
@@ -215,12 +228,12 @@
          * construct a key and iv (if necessary) suitable for use with a 
          * Cipher.
          */
-        static CipherParameters makePBEParameters(
-            PBEKeySpec              keySpec,
-            int                     type,
-            int                     hash,
-            int                     keySize,
-            int                     ivSize)
+        public static CipherParameters makePBEParameters(
+            PBEKeySpec keySpec,
+            int type,
+            int hash,
+            int keySize,
+            int ivSize)
         {    
             PBEParametersGenerator  generator = makePBEGenerator(type, hash);
             byte[]                  key;
@@ -259,11 +272,11 @@
          * key size is chosen according the MAC size, or the hashing algorithm,
          * whichever is greater.
          */
-        static CipherParameters makePBEMacParameters(
-            PBEKeySpec              keySpec,
-            int                     type,
-            int                     hash,
-            int                     keySize)
+        public static CipherParameters makePBEMacParameters(
+            PBEKeySpec keySpec,
+            int type,
+            int hash,
+            int keySize)
         {
             PBEParametersGenerator  generator = makePBEGenerator(type, hash);
             byte[]                  key;
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
new file mode 100644
index 0000000..f00ad36
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+
+public class PBESecretKeyFactory
+    extends BaseSecretKeyFactory
+    implements PBE
+{
+    private boolean forCipher;
+    private int scheme;
+    private int digest;
+    private int keySize;
+    private int ivSize;
+
+    public PBESecretKeyFactory(
+        String algorithm,
+        DERObjectIdentifier oid,
+        boolean forCipher,
+        int scheme,
+        int digest,
+        int keySize,
+        int ivSize)
+    {
+        super(algorithm, oid);
+
+        this.forCipher = forCipher;
+        this.scheme = scheme;
+        this.digest = digest;
+        this.keySize = keySize;
+        this.ivSize = ivSize;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PBEKeySpec)
+        {
+            PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+            CipherParameters param;
+
+            if (pbeSpec.getSalt() == null)
+            {
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+            }
+
+            if (forCipher)
+            {
+                param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+            }
+            else
+            {
+                param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+            }
+
+            return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+        }
+
+        throw new InvalidKeySpecException("Invalid KeySpec");
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java b/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java
new file mode 100644
index 0000000..50fe939
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+
+public abstract class AlgorithmProvider
+{
+    public abstract void configure(ConfigurableProvider provider);
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
new file mode 100644
index 0000000..c401084
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+
+public abstract class AsymmetricAlgorithmProvider
+    extends AlgorithmProvider
+{       
+    protected void addSignatureAlgorithm(
+        ConfigurableProvider provider,
+        String digest,
+        String algorithm,
+        String className,
+        ASN1ObjectIdentifier oid)
+    {
+        String mainName = digest + "WITH" + algorithm;
+        String jdk11Variation1 = digest + "with" + algorithm;
+        String jdk11Variation2 = digest + "With" + algorithm;
+        String alias = digest + "/" + algorithm;
+
+        provider.addAlgorithm("Signature." + mainName, className);
+        provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+    }
+
+    protected void registerOid(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name, AsymmetricKeyInfoConverter keyFactory)
+    {
+        provider.addAlgorithm("Alg.Alias.KeyFactory." + oid, name);
+        provider.addAlgorithm("Alg.Alias.KeyPairGenerator." + oid, name);
+
+        provider.addKeyInfoConverter(oid, keyFactory);
+    }
+
+    protected void registerOidAlgorithmParameters(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+    {
+        provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + oid, name);
+        provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + oid, name);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java b/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
new file mode 100644
index 0000000..e2f4e4a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public interface AsymmetricKeyInfoConverter
+{
+    PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException;
+
+    PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException;
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDigestUtil.java b/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
similarity index 76%
rename from src/main/java/org/bouncycastle/jce/provider/JCEDigestUtil.java
rename to src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
index 8f30b25..c56f192 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDigestUtil.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
@@ -1,26 +1,29 @@
-package org.bouncycastle.jce.provider;
+package org.bouncycastle.jcajce.provider.util;
 
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.MD5Digest;
-import org.bouncycastle.crypto.digests.SHA1Digest;
 // BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.SHA1Digest;
 // import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
 // END android-removed
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
 import org.bouncycastle.util.Strings;
 
-class JCEDigestUtil
+public class DigestFactory
 {
     private static Set md5 = new HashSet();
     private static Set sha1 = new HashSet();
@@ -86,18 +89,22 @@
         oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512); 
     }
     
-    static Digest getDigest(
+    public static Digest getDigest(
         String digestName) 
     {
         digestName = Strings.toUpperCase(digestName);
         
         if (sha1.contains(digestName))
         {
-            return new SHA1Digest();
+            // BEGIN android-changed
+            return new OpenSSLDigest.SHA1();
+            // END android-changed
         }
         if (md5.contains(digestName))
         {
-            return new MD5Digest();
+            // BEGIN android-changed
+            return new OpenSSLDigest.MD5();
+            // END android-changed
         }
         // BEGIN android-removed
         // if (sha224.contains(digestName))
@@ -107,21 +114,27 @@
         // END android-removed
         if (sha256.contains(digestName))
         {
-            return new SHA256Digest();
+            // BEGIN android-changed
+            return new OpenSSLDigest.SHA256();
+            // END android-changed
         }
         if (sha384.contains(digestName))
         {
-            return new SHA384Digest();
+            // BEGIN android-changed
+            return new OpenSSLDigest.SHA384();
+            // END android-changed
         }
         if (sha512.contains(digestName))
         {
-            return new SHA512Digest();
+            // BEGIN android-changed
+            return new OpenSSLDigest.SHA512();
+            // END android-changed
         }
         
         return null;
     }
     
-    static boolean isSameDigest(
+    public static boolean isSameDigest(
         String digest1,
         String digest2)
     {
@@ -135,9 +148,9 @@
             || (md5.contains(digest1) && md5.contains(digest2));
     }
     
-    static DERObjectIdentifier getOID(
+    public static ASN1ObjectIdentifier getOID(
         String digestName)
     {
-        return (DERObjectIdentifier)oids.get(digestName);
+        return (ASN1ObjectIdentifier)oids.get(digestName);
     }
 }
diff --git a/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
index 5c0fe7d..b56351b 100644
--- a/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
+++ b/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
@@ -1,6 +1,9 @@
 package org.bouncycastle.jce;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+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
@@ -10,9 +13,6 @@
 import org.bouncycastle.asn1.x9.X9ECParameters;
 import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
 
-import java.util.Enumeration;
-import java.util.Vector;
-
 /**
  * a table of locally supported named curves.
  */
@@ -33,7 +33,7 @@
         {
             try
             {
-                ecP = X962NamedCurves.getByOID(new DERObjectIdentifier(name));
+                ecP = X962NamedCurves.getByOID(new ASN1ObjectIdentifier(name));
             }
             catch (IllegalArgumentException e)
             {
@@ -48,7 +48,7 @@
             {
                 try
                 {
-                    ecP = SECNamedCurves.getByOID(new DERObjectIdentifier(name));
+                    ecP = SECNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
                 }
                 catch (IllegalArgumentException e)
                 {
@@ -65,7 +65,7 @@
         //     {
         //         try
         //         {
-        //             ecP = TeleTrusTNamedCurves.getByOID(new DERObjectIdentifier(name));
+        //             ecP = TeleTrusTNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
         //         }
         //         catch (IllegalArgumentException e)
         //         {
diff --git a/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
index ad1cfb2..88ac2b1 100644
--- a/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
+++ b/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -21,13 +21,13 @@
 import javax.security.auth.x500.X500Principal;
 
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
@@ -37,7 +37,9 @@
 import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509Name;
@@ -68,6 +70,7 @@
  *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
  *  }
  * </pre>
+ * @deprecated use classes in org.bouncycastle.pkcs.
  */
 public class PKCS10CertificationRequest
     extends CertificationRequest
@@ -241,8 +244,8 @@
         return new RSASSAPSSparams(
             hashAlgId,
             new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
-            new DERInteger(saltSize),
-            new DERInteger(1));
+            new ASN1Integer(saltSize),
+            new ASN1Integer(1));
     }
 
     private static ASN1Sequence toDERSequence(
@@ -379,7 +382,7 @@
         }
         else if (params.containsKey(algorithmName))
         {
-            this.sigAlgId = new AlgorithmIdentifier(sigOID, (DEREncodable)params.get(algorithmName));
+            this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
         }
         else
         {
@@ -388,7 +391,7 @@
 
         try
         {
-            ASN1Sequence seq = (ASN1Sequence)ASN1Object.fromByteArray(key.getEncoded());
+            ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
             this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes);
         }
         catch (IOException e)
@@ -410,7 +413,7 @@
 
         try
         {
-            sig.update(reqInfo.getEncoded(ASN1Encodable.DER));
+            sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
         }
         catch (Exception e)
         {
@@ -553,7 +556,7 @@
 
         try
         {
-            sig.update(reqInfo.getEncoded(ASN1Encodable.DER));
+            sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
         }
         catch (Exception e)
         {
@@ -570,7 +573,7 @@
     {
         try
         {
-            return this.getEncoded(ASN1Encodable.DER);
+            return this.getEncoded(ASN1Encoding.DER);
         }
         catch (IOException e)
         {
@@ -580,7 +583,7 @@
 
     private void setSignatureParameters(
         Signature signature,
-        DEREncodable params)
+        ASN1Encodable params)
         throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
     {
         if (params != null && !DERNull.INSTANCE.equals(params))
@@ -589,7 +592,7 @@
 
             try
             {
-                sigParams.init(params.getDERObject().getDEREncoded());
+                sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
             }
             catch (IOException e)
             {
@@ -613,7 +616,7 @@
     static String getSignatureName(
         AlgorithmIdentifier sigAlgId)
     {
-        DEREncodable params = sigAlgId.getParameters();
+        ASN1Encodable params = sigAlgId.getParameters();
 
         if (params != null && !DERNull.INSTANCE.equals(params))
         {
diff --git a/src/main/java/org/bouncycastle/jce/PrincipalUtil.java b/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
index 6ccf1e4..4bf65a0 100644
--- a/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
+++ b/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
@@ -1,10 +1,15 @@
 package org.bouncycastle.jce;
 
-import java.io.*;
-import java.security.cert.*;
+import java.io.IOException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
 
-import org.bouncycastle.asn1.*;
-import org.bouncycastle.asn1.x509.*;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
 
 /**
  * a utility class that will extract X509Principal objects from X.509 certificates.
@@ -25,9 +30,9 @@
         try
         {
             TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
-                    ASN1Object.fromByteArray(cert.getTBSCertificate()));
+                    ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
 
-            return new X509Principal(tbsCert.getIssuer());
+            return new X509Principal(X509Name.getInstance(tbsCert.getIssuer()));
         }
         catch (IOException e)
         {
@@ -45,8 +50,8 @@
         try
         {
             TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
-                    ASN1Object.fromByteArray(cert.getTBSCertificate()));
-            return new X509Principal(tbsCert.getSubject());
+                    ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+            return new X509Principal(X509Name.getInstance(tbsCert.getSubject()));
         }
         catch (IOException e)
         {
@@ -64,9 +69,9 @@
         try
         {
             TBSCertList tbsCertList = TBSCertList.getInstance(
-                ASN1Object.fromByteArray(crl.getTBSCertList()));
+                ASN1Primitive.fromByteArray(crl.getTBSCertList()));
 
-            return new X509Principal(tbsCertList.getIssuer());
+            return new X509Principal(X509Name.getInstance(tbsCertList.getIssuer()));
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/jce/X509Principal.java b/src/main/java/org/bouncycastle/jce/X509Principal.java
index 9cc5538..efa0f66 100644
--- a/src/main/java/org/bouncycastle/jce/X509Principal.java
+++ b/src/main/java/org/bouncycastle/jce/X509Principal.java
@@ -5,9 +5,10 @@
 import java.util.Hashtable;
 import java.util.Vector;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.X509Name;
 
 /**
@@ -53,7 +54,16 @@
     public X509Principal(
         X509Name  name)
     {
-        super((ASN1Sequence)name.getDERObject());
+        super((ASN1Sequence)name.toASN1Primitive());
+    }
+
+     /**
+     * Constructor from an X509Name object.
+     */
+    public X509Principal(
+        X500Name name)
+    {
+        super((ASN1Sequence)name.toASN1Primitive());
     }
 
     /**
@@ -144,7 +154,7 @@
     {
         try
         {
-            return this.getEncoded(ASN1Encodable.DER);
+            return this.getEncoded(ASN1Encoding.DER);
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/jce/interfaces/ConfigurableProvider.java b/src/main/java/org/bouncycastle/jce/interfaces/ConfigurableProvider.java
deleted file mode 100644
index 5aa2d9c..0000000
--- a/src/main/java/org/bouncycastle/jce/interfaces/ConfigurableProvider.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.bouncycastle.jce.interfaces;
-
-/**
- * Implemented by the BC provider. This allows setting of hidden parameters,
- * such as the ImplicitCA parameters from X.962, if used.
- */
-public interface ConfigurableProvider
-{
-    static final String      THREAD_LOCAL_EC_IMPLICITLY_CA = "threadLocalEcImplicitlyCa";   
-    static final String      EC_IMPLICITLY_CA = "ecImplicitlyCa";
-
-    void setParameter(String parameterName, Object parameter);
-}
diff --git a/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java b/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
index f27652e..cbc9f44 100644
--- a/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
+++ b/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
@@ -2,7 +2,8 @@
 
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 
 /**
@@ -11,10 +12,10 @@
 public interface PKCS12BagAttributeCarrier
 {
     void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute);
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute);
 
-    DEREncodable getBagAttribute(
+    ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid);
 
     Enumeration getBagAttributeKeys();
diff --git a/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
index 5179298..4bfb9d9 100644
--- a/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
+++ b/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
@@ -15,13 +15,14 @@
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
 
-import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -42,7 +43,7 @@
  *
  **/
 public class NetscapeCertRequest
-    extends ASN1Encodable
+    extends ASN1Object
 {
     AlgorithmIdentifier    sigAlg;
     AlgorithmIdentifier    keyAlg;
@@ -217,7 +218,7 @@
             SignatureException, NoSuchProviderException,
             InvalidKeySpecException
     {
-        Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
+        Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
                 "BC");
 
         if (rand != null)
@@ -236,7 +237,7 @@
 
         try
         {
-            sig.update(new DERSequence(pkac).getEncoded(ASN1Encodable.DER));
+            sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
         }
         catch (IOException ioe)
         {
@@ -246,12 +247,12 @@
         sigBits = sig.sign();
     }
 
-    private DERObject getKeySpec() throws NoSuchAlgorithmException,
+    private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
             InvalidKeySpecException, NoSuchProviderException
     {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 
-        DERObject obj = null;
+        ASN1Primitive obj = null;
         try
         {
 
@@ -270,7 +271,7 @@
         return obj;
     }
 
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector spkac = new ASN1EncodableVector();
         ASN1EncodableVector pkac = new ASN1EncodableVector();
diff --git a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index f712938..5ed4df9 100644
--- a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -1,20 +1,23 @@
 package org.bouncycastle.jce.provider;
 
+import java.io.IOException;
 import java.security.AccessController;
+import java.security.PrivateKey;
 import java.security.PrivilegedAction;
 import java.security.Provider;
-import java.util.Iterator;
+import java.security.PublicKey;
+import java.util.HashMap;
 import java.util.Map;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
-import org.bouncycastle.jce.interfaces.ConfigurableProvider;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
 
 /**
  * To add the provider at runtime use:
@@ -43,36 +46,67 @@
 public final class BouncyCastleProvider extends Provider
     implements ConfigurableProvider
 {
-    private static String info = "BouncyCastle Security Provider v1.46";
+    private static String info = "BouncyCastle Security Provider v1.47";
 
     // BEGIN android-changed
     //     this constant should be final
     public static final String PROVIDER_NAME = "BC";
     // END android-changed
 
+    public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
+
+
+    private static final Map keyInfoConverters = new HashMap();
+
     /*
      * Configurable symmetric ciphers
      */
-    private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.symmetric.";
+    private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric.";
     private static final String[] SYMMETRIC_CIPHERS =
     {
         // BEGIN android-removed
-        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
-        // "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
+        // "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"
         // END android-removed
         // BEGIN android-added
-        "AES", "ARC4", "Blowfish", "DESede",
+        "AES", "ARC4", "Blowfish", "DES", "DESede",
         // END android-added
+    };
 
+     /*
+     * Configurable asymmetric ciphers
+     */
+    private static final String ASYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric.";
+
+    // this one is required for GNU class path - it needs to be loaded first as the
+    // later ones configure it.
+    private static final String[] ASYMMETRIC_GENERIC =
+    {
+        "X509"
+    };
+
+    private static final String[] ASYMMETRIC_CIPHERS =
+    {
+        // BEGIN android-removed
+        // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal"
+        // END android-removed
+        // BEGIN android-added
+        "DSA", "DH", "EC", "RSA",
+        // END android-added
     };
 
     /*
-     * Configurable asymmetric ciphers
+     * Configurable digests
      */
-    private static final String ASYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.asymmetric.";
-    private static final String[] ASYMMETRIC_CIPHERS =
+    private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
+    private static final String[] DIGESTS =
     {
-        "EC"
+        // BEGIN android-removed
+        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "Tiger", "Whirlpool"
+        // END android-removed
+        // BEGIN android-added
+        "MD5", "SHA1", "SHA256", "SHA384", "SHA512",
+        // END android-added
     };
 
     /**
@@ -82,7 +116,7 @@
      */
     public BouncyCastleProvider()
     {
-        super(PROVIDER_NAME, 1.46, info);
+        super(PROVIDER_NAME, 1.47, info);
 
         AccessController.doPrivileged(new PrivilegedAction()
         {
@@ -96,7 +130,12 @@
 
     private void setup()
     {
+        loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
+
         loadAlgorithms(SYMMETRIC_CIPHER_PACKAGE, SYMMETRIC_CIPHERS);
+
+        loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_GENERIC);
+
         loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_CIPHERS);
 
         // BEGIN android-removed
@@ -153,56 +192,18 @@
         put("Alg.Alias.KeyStore.bouncycastle", "BouncyCastle");
 
         //
-        // certificate factories.
-        //
-        put("CertificateFactory.X.509", "org.bouncycastle.jce.provider.JDKX509CertificateFactory");
-        put("Alg.Alias.CertificateFactory.X509", "X.509");
-
-        //
-        // algorithm parameter generators
-        //
-        put("AlgorithmParameterGenerator.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DH");
-        put("AlgorithmParameterGenerator.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DSA");
-        // BEGIN android-removed
-        // put("AlgorithmParameterGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$GOST3410");
-        // put("AlgorithmParameterGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$ElGamal");
-        // put("AlgorithmParameterGenerator.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-        // put("AlgorithmParameterGenerator.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-        // put("AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-        // put("AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
-        // put("AlgorithmParameterGenerator.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
-        // put("AlgorithmParameterGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
-        // END android-removed
-
-        put("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH");
-        // BEGIN android-removed
-        // put("Alg.Alias.AlgorithmParameterGenerator.GOST-3410", "GOST3410");
-        // END android-removed
-        //
         // algorithm parameters
         //
-        put("AlgorithmParameters.OAEP", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$OAEP");
         // BEGIN android-removed
-        // put("AlgorithmParameters.PSS", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PSS");
-        // END android-removed
-        put("AlgorithmParameters.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$DH");
-        put("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH");
-        put("AlgorithmParameters.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$DSA");
-        // BEGIN android-removed
-        // put("AlgorithmParameters.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$ElGamal");
         // put("AlgorithmParameters.IES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IES");
         // END android-removed
         put("AlgorithmParameters.PKCS12PBE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PKCS12PBE");
-        // BEGIN android-changed
-        // redundant with below
-        // put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
-        // END android-changed
+
         // BEGIN android-removed
         // put("AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PBKDF2");
-        //
-        // put("AlgorithmParameters.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$GOST3410");
-        // put("Alg.Alias.AlgorithmParameters.GOST-3410", "GOST3410");
         // END android-removed
+
+
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
         // BEGIN android-removed
         // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE");
@@ -225,7 +226,9 @@
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC4", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
-        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
+        // BEGIN android-removed
+        // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
+        // END android-removed
         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.1", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.2", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3", "PKCS12PBE");
@@ -233,7 +236,7 @@
         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
-        
+
         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
@@ -241,27 +244,6 @@
         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
 
-        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
-        
-        // BEGIN android-removed
-        // put("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
-        // put("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
-        // END android-removed
-        
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
         put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND256BITAES-CBC-BC", "PKCS12PBE");
@@ -289,64 +271,19 @@
         //
         // key agreement
         //
-        put("KeyAgreement.DH", "org.bouncycastle.jce.provider.JCEDHKeyAgreement");
-        put("Alg.Alias.KeyAgreement.DIFFIEHELLMAN", "DH");
+
         
         //
         // cipher engines
         //
-        put("Cipher.DES", "org.bouncycastle.jce.provider.JCEBlockCipher$DES");
-        // BEGIN android-removed
-        // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
-        //
-        // put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
-        // put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
-        // put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
-        //
-        // put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
-        // END android-removed
-        
         put("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES",  "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
         
-        // BEGIN android-removed
-        // put("Cipher.GOST28147", "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147");
-        // put("Alg.Alias.Cipher.GOST", "GOST28147");
-        // put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
-        // put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
-        // END android-removed
 
-        put("Cipher.RSA", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
-        // BEGIN android-changed
-        put("Alg.Alias.Cipher.RSA/RAW", "RSA");
-        // END android-changed
         // BEGIN android-removed
-        // put("Cipher.RSA/PKCS1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
-        // put("Cipher.1.2.840.113549.1.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
-        // put("Cipher.2.5.8.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
-        // put("Cipher.RSA/1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PrivateOnly");
-        // put("Cipher.RSA/2", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PublicOnly");
-        // put("Cipher.RSA/OAEP", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
-        // put("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
-        // put("Cipher.RSA/ISO9796-1", "org.bouncycastle.jce.provider.JCERSACipher$ISO9796d1Padding");
-        //
         // put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
         // put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
         // put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
         // put("Cipher.BrokenIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenIES");
-        // put("Cipher.ELGAMAL", "org.bouncycastle.jce.provider.JCEElGamalCipher$NoPadding");
-        // put("Cipher.ELGAMAL/PKCS1", "org.bouncycastle.jce.provider.JCEElGamalCipher$PKCS1v1_5Padding");
-        // END android-removed
-
-        put("Alg.Alias.Cipher.RSA//RAW", "RSA");
-        put("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
-        // BEGIN android-removed
-        // put("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
-        // put("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
-        // put("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
-        //
-        // put("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
-        // put("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
-        // put("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
         // END android-removed
 
         put("Cipher.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithMD5AndDES");
@@ -359,28 +296,17 @@
         // put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
         // END android-removed
         put("Cipher.PBEWITHSHA1ANDRC2", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHA1AndRC2");
-        put("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndDES3Key");
-        // BEGIN android-removed
-        // put("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES3Key");
-        // put("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndDES3Key");
-        // END android-removed
-        put("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndDES2Key");
-        // BEGIN android-removed
-        // put("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES2Key");
-        // END android-removed
+
         put("Cipher.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd128BitRC2");
         put("Cipher.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd40BitRC2");
         put("Cipher.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd128BitRC4");
         put("Cipher.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd40BitRC4");
 
-        // BEGIN android-changed
-        put("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
-        put("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+
         put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
-        // END android-changed
 
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
@@ -388,7 +314,7 @@
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
-        
+
         put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
         put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
         put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
@@ -423,94 +349,38 @@
 
         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
-        put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
-        put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+
         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
-        put("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+
         //
         // key generators.
         //
-        put("KeyGenerator.DES", "org.bouncycastle.jce.provider.JCEKeyGenerator$DES");
-        put("Alg.Alias.KeyGenerator." + OIWObjectIdentifiers.desCBC, "DES");
 
-        // BEGIN android-removed
-        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-        //
-        // put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
-        // put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
-        // put("Alg.Alias.KeyGenerator.GOST-28147", "GOST28147");
-        // put("Alg.Alias.KeyGenerator." + CryptoProObjectIdentifiers.gostR28147_cbc, "GOST28147");
-        // END android-removed
 
         //
         // key pair generators.
         //
-        put("KeyPairGenerator.RSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$RSA");
-        put("KeyPairGenerator.DH", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DH");
-        put("KeyPairGenerator.DSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DSA");
-        // BEGIN android-removed
-        // put("KeyPairGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ElGamal");
-        // END android-removed
 
-        put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.1", "RSA");
-        put("Alg.Alias.KeyPairGenerator.DIFFIEHELLMAN", "DH");
-        
-        // BEGIN android-removed
-        // put("KeyPairGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$GOST3410");
-        // put("Alg.Alias.KeyPairGenerator.GOST-3410", "GOST3410");
-        // put("Alg.Alias.KeyPairGenerator.GOST-3410-94", "GOST3410");
-        // END android-removed
+
 
         //
         // key factories
         //
-        put("KeyFactory.RSA", "org.bouncycastle.jce.provider.JDKKeyFactory$RSA");
-        put("KeyFactory.DH", "org.bouncycastle.jce.provider.JDKKeyFactory$DH");
-        put("KeyFactory.DSA", "org.bouncycastle.jce.provider.JDKKeyFactory$DSA");
-        // BEGIN android-removed
-        // put("KeyFactory.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
-        // put("KeyFactory.ElGamal", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
-        //
-        // put("KeyFactory.X.509", "org.bouncycastle.jce.provider.JDKKeyFactory$X509");
-        // END android-removed
-        
-        put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA");
-        put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA");
 
-        put("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH");
 
-        // BEGIN android-removed
-        // put("KeyFactory.GOST3410", "org.bouncycastle.jce.provider.JDKKeyFactory$GOST3410");
-        // put("Alg.Alias.KeyFactory.GOST-3410", "GOST3410");
-        // put("Alg.Alias.KeyFactory.GOST-3410-94", "GOST3410");
-        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_94, "GOST3410");
-        // END android-removed
+
 
         //
         // Algorithm parameters
         //
-        put("AlgorithmParameters.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        put("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
-        put("AlgorithmParameters.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        // BEGIN android-changed
-        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
-        // END android-changed
-        // BEGIN android-removed
-        // put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-        // put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-        // END android-removed
-        
+
         //
         // secret key factories.
         //
-        put("SecretKeyFactory.DES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DES");
         // BEGIN android-removed
         // put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
-        // END android-removed
-
-        // BEGIN android-removed
+        //
         // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
         // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
         // END android-removed
@@ -554,9 +424,7 @@
         // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PBE/PKCS12");
         // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBE/PKCS12");
         // put("Alg.Alias.SecretKeyFactory.OLDPBEWITHSHAANDTWOFISH-CBC", "PBE/PKCS12");
-        // END android-removed
-
-        // BEGIN android-removed
+        //
         // put("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
         // put("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDRC2-CBC", "PBEWITHMD2ANDRC2");
         // END android-removed
@@ -611,10 +479,6 @@
 
         addMacAlgorithms();
 
-        addMessageDigestAlgorithms();
-
-        addSignatureAlgorithms();
-
     // Certification Path API
         // BEGIN android-removed
         // put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
@@ -662,10 +526,11 @@
             {
                 try
                 {
-                    addMappings((Map)clazz.newInstance());
+                    ((AlgorithmProvider)clazz.newInstance()).configure(this);
                 }
                 catch (Exception e)
                 {   // this should never ever happen!!
+e.printStackTrace();
                     throw new InternalError("cannot create instance of "
                         + packageName + names[i] + "$Mappings : " + e);
                 }
@@ -673,32 +538,13 @@
         }
     }
 
-    private void addMappings(Map mappings)
-    {
-        // can't use putAll due to JDK 1.1
-        for (Iterator it = mappings.keySet().iterator(); it.hasNext();)
-        {
-            Object key = it.next();
-
-            if (containsKey(key))
-            {
-                throw new IllegalStateException("duplicate provider key (" + key + ") found in " + mappings.getClass().getName());
-            }
-            put(key, mappings.get(key));
-        }
-    }
-
     //
     // macs
     //
     private void addMacAlgorithms()
     {
+
         // BEGIN android-removed
-        // put("Mac.DESMAC", "org.bouncycastle.jce.provider.JCEMac$DES");
-        // put("Alg.Alias.Mac.DES", "DESMAC");
-        // put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
-        // put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
-        //
         // put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
         // put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
         //
@@ -707,46 +553,9 @@
         // put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
         // put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
         //
-        // put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
-        // put("Alg.Alias.Mac.RC2", "RC2MAC");
-        // put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
-        // put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
-        //
-        //
-        // put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
-        // put("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
-        //
         // put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
         //
         // put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
-        //
-        // addHMACAlgorithm("MD2", "org.bouncycastle.jce.provider.JCEMac$MD2", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD2HMAC");
-        // addHMACAlgorithm("MD4", "org.bouncycastle.jce.provider.JCEMac$MD4", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD4HMAC");
-        // END android-removed
-        addHMACAlgorithm("MD5", "org.bouncycastle.jce.provider.JCEMac$MD5", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD5HMAC");
-        addHMACAlias("MD5", IANAObjectIdentifiers.hmacMD5);
-
-        addHMACAlgorithm("SHA1", "org.bouncycastle.jce.provider.JCEMac$SHA1", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA1");
-        addHMACAlias("SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
-        addHMACAlias("SHA1", IANAObjectIdentifiers.hmacSHA1);
-        // BEGIN android-removed
-        // addHMACAlgorithm("SHA224", "org.bouncycastle.jce.provider.JCEMac$SHA224", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA224");
-        // addHMACAlias("SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
-        // END android-removed
-        addHMACAlgorithm("SHA256", "org.bouncycastle.jce.provider.JCEMac$SHA256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA256");
-        addHMACAlias("SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
-        addHMACAlgorithm("SHA384", "org.bouncycastle.jce.provider.JCEMac$SHA384", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA384");
-        addHMACAlias("SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
-        addHMACAlgorithm("SHA512", "org.bouncycastle.jce.provider.JCEMac$SHA512", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA512");
-        addHMACAlias("SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
-
-        // BEGIN android-removed
-        // addHMACAlgorithm("RIPEMD128", "org.bouncycastle.jce.provider.JCEMac$RIPEMD128", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD128HMAC");
-        // addHMACAlgorithm("RIPEMD160", "org.bouncycastle.jce.provider.JCEMac$RIPEMD160", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD160HMAC");
-        // addHMACAlias("RIPEMD160", IANAObjectIdentifiers.hmacRIPEMD160);
-        //
-        // addHMACAlgorithm("TIGER", "org.bouncycastle.jce.provider.JCEMac$Tiger", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACTIGER");
-        // addHMACAlias("TIGER", IANAObjectIdentifiers.hmacTIGER);
         // END android-removed
 
         put("Mac.PBEWITHHMACSHA", "org.bouncycastle.jce.provider.JCEMac$PBEWithSHA");
@@ -757,304 +566,63 @@
         put("Alg.Alias.Mac.1.3.14.3.2.26", "PBEWITHHMACSHA");
     }
 
-    private void addHMACAlgorithm(
-        String algorithm,
-        String algorithmClassName,
-        String keyGeneratorClassName)
-    {
-        String mainName = "HMAC" + algorithm;
-
-        put("Mac." + mainName, algorithmClassName);
-        put("Alg.Alias.Mac.HMAC-" + algorithm, mainName);
-        put("Alg.Alias.Mac.HMAC/" + algorithm, mainName);
-        put("KeyGenerator." + mainName, keyGeneratorClassName);
-        put("Alg.Alias.KeyGenerator.HMAC-" + algorithm, mainName);
-        put("Alg.Alias.KeyGenerator.HMAC/" + algorithm, mainName);
-    }
-
-    private void addHMACAlias(
-        String              algorithm,
-        DERObjectIdentifier oid)
-    {
-        String mainName = "HMAC" + algorithm;
-
-        put("Alg.Alias.Mac." + oid, mainName);
-        put("Alg.Alias.KeyGenerator." + oid, mainName);
-    }
-
-    //
-    // message digests
-    //
-    private void addMessageDigestAlgorithms()
-    {
-        put("MessageDigest.SHA-1", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA1");
-        put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
-        put("Alg.Alias.MessageDigest.SHA", "SHA-1");
-        put("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
-        // BEGIN android-removed
-        // put("MessageDigest.SHA-224", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA224");
-        // put("Alg.Alias.MessageDigest.SHA224", "SHA-224");
-        // put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
-        // END android-removed
-        put("MessageDigest.SHA-256", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA256");
-        put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
-        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
-        put("MessageDigest.SHA-384", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA384");
-        put("Alg.Alias.MessageDigest.SHA384", "SHA-384");
-        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
-        put("MessageDigest.SHA-512", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA512");
-        put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
-        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
-        
-        // BEGIN android-removed
-        // put("MessageDigest.MD2", "org.bouncycastle.jce.provider.JDKMessageDigest$MD2");
-        // put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md2, "MD2");
-        // put("MessageDigest.MD4", "org.bouncycastle.jce.provider.JDKMessageDigest$MD4");
-        // put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md4, "MD4");
-        // END android-removed
-        put("MessageDigest.MD5", "org.bouncycastle.jce.provider.JDKMessageDigest$MD5");
-        put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
-        // BEGIN android-removed
-        // put("MessageDigest.RIPEMD128", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD128");
-        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
-        // put("MessageDigest.RIPEMD160", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD160");
-        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
-        // put("MessageDigest.RIPEMD256", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD256");
-        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
-        // put("MessageDigest.RIPEMD320", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD320");
-        // put("MessageDigest.Tiger", "org.bouncycastle.jce.provider.JDKMessageDigest$Tiger");
-        
-        // put("MessageDigest.WHIRLPOOL", "org.bouncycastle.jce.provider.JDKMessageDigest$Whirlpool");
-        
-        // put("MessageDigest.GOST3411", "org.bouncycastle.jce.provider.JDKMessageDigest$GOST3411");
-        // put("Alg.Alias.MessageDigest.GOST", "GOST3411");
-        // put("Alg.Alias.MessageDigest.GOST-3411", "GOST3411");
-        // put("Alg.Alias.MessageDigest." + CryptoProObjectIdentifiers.gostR3411, "GOST3411");
-        // END android-removed
-    }
-    
-    //
-    // signature algorithms.
-    //
-    private void addSignatureAlgorithms()
-    {
-        // BEGIN android-removed
-        // Dropping MD2
-        // put("Signature.MD2WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD2WithRSAEncryption");
-        // put("Signature.MD4WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD4WithRSAEncryption");
-        // END android-removed
-        put("Signature.MD5WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD5WithRSAEncryption");
-        put("Signature.SHA1WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA1WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Signature.SHA224WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA224WithRSAEncryption");
-        // END android-removed
-        put("Signature.SHA256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA256WithRSAEncryption");
-        put("Signature.SHA384WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA384WithRSAEncryption");
-        put("Signature.SHA512WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA512WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Signature.RIPEMD160WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD160WithRSAEncryption");
-        // put("Signature.RIPEMD128WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD128WithRSAEncryption");
-        // put("Signature.RIPEMD256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD256WithRSAEncryption");
-        // END android-removed
-        // BEGIN android-changed
-        put("Signature.SHA1withDSA", "org.bouncycastle.jce.provider.JDKDSASigner$stdDSA");
-        // END android-changed
-        put("Signature.NONEWITHDSA", "org.bouncycastle.jce.provider.JDKDSASigner$noneDSA");
-        // BEGIN android-removed
-        // put("Signature.SHA1withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$SHA1WithRSAEncryption");
-        // put("Signature.MD5withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$MD5WithRSAEncryption");
-        // put("Signature.RIPEMD160withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$RIPEMD160WithRSAEncryption");
-        //
-        // put("Signature.RSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
-        // put("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
-        // put("Signature.SHA1withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA1withRSA");
-        // put("Signature.SHA224withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA224withRSA");
-        // put("Signature.SHA256withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA256withRSA");
-        // put("Signature.SHA384withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA384withRSA");
-        // put("Signature.SHA512withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA512withRSA");
-        //
-        // put("Signature.RSA", "org.bouncycastle.jce.provider.JDKDigestSignature$noneRSA");
-        // put("Signature.RAWRSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$nonePSS");
-        // END android-removed
-
-        put("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
-
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.RAWRSA", "RSA");
-        // put("Alg.Alias.Signature.NONEWITHRSA", "RSA");
-        // put("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
-        // put("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
-        // put("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
-        //
-        // put("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
-        //
-        // put("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
-        // put("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
-        // put("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
-        // put("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
-        // put("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
-        //
-        // put("Alg.Alias.Signature.MD2withRSAEncryption", "MD2WithRSAEncryption");
-        // put("Alg.Alias.Signature.MD4withRSAEncryption", "MD4WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature.MD5withRSAEncryption", "MD5WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA1withRSAEncryption", "SHA1WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.SHA224withRSAEncryption", "SHA224WithRSAEncryption");
-        // END android-removed
-
-        put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA512withRSAEncryption", "SHA512WithRSAEncryption");
-
-        put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512WithRSAEncryption");
-
-        put("Alg.Alias.Signature.SHA256WITHRSAENCRYPTION", "SHA256WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA384WITHRSAENCRYPTION", "SHA384WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA512WITHRSAENCRYPTION", "SHA512WithRSAEncryption");
-
-        // BEGIN android-removed
-        // Dropping MD2
-        // put("Alg.Alias.Signature.RIPEMD160withRSAEncryption", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WithRSAEncryption");
-        // put("Alg.Alias.Signature.MD2WithRSA", "MD2WithRSAEncryption");
-        // put("Alg.Alias.Signature.MD2withRSA", "MD2WithRSAEncryption");
-        // put("Alg.Alias.Signature.MD2/RSA", "MD2WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature.MD5WithRSA", "MD5WithRSAEncryption");
-        put("Alg.Alias.Signature.MD5withRSA", "MD5WithRSAEncryption");
-        put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSAEncryption");
-        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.MD4WithRSA", "MD4WithRSAEncryption");
-        // put("Alg.Alias.Signature.MD4withRSA", "MD4WithRSAEncryption");
-        // put("Alg.Alias.Signature.MD4/RSA", "MD4WithRSAEncryption");
-        // put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA1withRSA", "SHA1WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.SHA224WithRSA", "SHA224WithRSAEncryption");
-        // put("Alg.Alias.Signature.SHA224withRSA", "SHA224WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA256withRSA", "SHA256WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA384withRSA", "SHA384WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA512WithRSA", "SHA512WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA512withRSA", "SHA512WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
-        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WithRSAEncryption");
-        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WithRSAEncryption");
-        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WithRSAEncryption");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSAEncryption");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
-        put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.RIPEMD160WithRSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD160withRSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD128WithRSA", "RIPEMD128WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD128withRSA", "RIPEMD128WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD256WithRSA", "RIPEMD256WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD256withRSA", "RIPEMD256WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD-160/RSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.RMD160withRSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.RMD160/RSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.1.3.36.3.3.1.2", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.1.3.36.3.3.1.3", "RIPEMD128WithRSAEncryption");
-        // put("Alg.Alias.Signature.1.3.36.3.3.1.4", "RIPEMD256WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WithRSAEncryption");
-        
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.MD2WITHRSAENCRYPTION", "MD2WithRSAEncryption");
-        // END android-removed
-        put("Alg.Alias.Signature.MD5WITHRSAENCRYPTION", "MD5WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA1WITHRSAENCRYPTION", "SHA1WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.RIPEMD160WITHRSAENCRYPTION", "RIPEMD160WithRSAEncryption");
-        // END android-removed
-
-        put("Alg.Alias.Signature.MD5WITHRSA", "MD5WithRSAEncryption");
-        put("Alg.Alias.Signature.SHA1WITHRSA", "SHA1WithRSAEncryption");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.RMD160WITHRSA", "RIPEMD160WithRSAEncryption");
-        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
-        // END android-removed
-
-        // BEGIN android-removed
-        // addSignatureAlgorithm("SHA224", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
-        // addSignatureAlgorithm("SHA256", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
-        // addSignatureAlgorithm("SHA384", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
-        // addSignatureAlgorithm("SHA512", "DSA", "org.bouncycastle.jce.provider.JDKDSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
-        // END android-removed
-
-        // BEGIN android-changed
-        put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
-        put("Alg.Alias.Signature.DSA", "SHA1withDSA");
-        put("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
-        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
-        put("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA");
-        put("Alg.Alias.Signature.DSAWITHSHA1", "SHA1withDSA");
-        put("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA");
-        put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
-        put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
-        // END android-changed
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
-        // put("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
-        // put("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
-        //
-        // put("Signature.ECGOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$ecgost3410");
-        // put("Alg.Alias.Signature.ECGOST-3410", "ECGOST3410");
-        // put("Alg.Alias.Signature.GOST-3410-2001", "ECGOST3410");
-        // put("Alg.Alias.Signature.GOST3411withECGOST3410", "ECGOST3410");
-        // put("Alg.Alias.Signature.GOST3411WITHECGOST3410", "ECGOST3410");
-        // put("Alg.Alias.Signature.GOST3411WithECGOST3410", "ECGOST3410");
-        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "ECGOST3410");
-        //
-        // put("Signature.GOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$gost3410");
-        // put("Alg.Alias.Signature.GOST-3410", "GOST3410");
-        // put("Alg.Alias.Signature.GOST-3410-94", "GOST3410");
-        // put("Alg.Alias.Signature.GOST3411withGOST3410", "GOST3410");
-        // put("Alg.Alias.Signature.GOST3411WITHGOST3410", "GOST3410");
-        // put("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
-        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
-        // END android-removed
-    }
-
-    // BEGIN android-removed
-    // private void addSignatureAlgorithm(
-    //     String digest,
-    //     String algorithm,
-    //     String className,
-    //     DERObjectIdentifier oid)
-    // {
-    //     String mainName = digest + "WITH" + algorithm;
-    //     String jdk11Variation1 = digest + "with" + algorithm;
-    //     String jdk11Variation2 = digest + "With" + algorithm;
-    //     String alias = digest + "/" + algorithm;
-    //
-    //     put("Signature." + mainName, className);
-    //     put("Alg.Alias.Signature." + jdk11Variation1, mainName);
-    //     put("Alg.Alias.Signature." + jdk11Variation2, mainName);
-    //     put("Alg.Alias.Signature." + alias, mainName);
-    //     put("Alg.Alias.Signature." + oid, mainName);
-    //     put("Alg.Alias.Signature.OID." + oid, mainName);
-    // }
-    // END android-removed
 
     public void setParameter(String parameterName, Object parameter)
     {
-        ProviderUtil.setParameter(parameterName, parameter);
+        synchronized (CONFIGURATION)
+        {
+            ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+        }
+    }
+
+    public boolean hasAlgorithm(String type, String name)
+    {
+        return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+    }
+
+    public void addAlgorithm(String key, String value)
+    {
+        if (containsKey(key))
+        {
+            throw new IllegalStateException("duplicate provider key (" + key + ") found");
+        }
+
+        put(key, value);
+    }
+
+    public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+    {
+        keyInfoConverters.put(oid, keyInfoConverter);
+    }
+
+    public AsymmetricKeyInfoConverter getConverter(ASN1ObjectIdentifier oid)
+    {
+        return (AsymmetricKeyInfoConverter)keyInfoConverters.get(oid);
+    }
+
+    public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+        throws IOException
+    {
+        AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+        if (converter == null)
+        {
+            return null;
+        }
+
+        return converter.generatePublic(publicKeyInfo);
+    }
+
+    public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+        throws IOException
+    {
+        AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+        if (converter == null)
+        {
+            return null;
+        }
+
+        return converter.generatePrivate(privateKeyInfo);
     }
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 0000000..b370ea9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.Permission;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+    implements ProviderConfiguration
+{
+    private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+    private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
+    private static Permission BC_DH_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
+    private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+
+    private ThreadLocal ecThreadSpec = new ThreadLocal();
+    private ThreadLocal dhThreadSpec = new ThreadLocal();
+
+    private volatile ECParameterSpec ecImplicitCaParams;
+    private volatile DHParameterSpec dhDefaultParams;
+
+    void setParameter(String parameterName, Object parameter)
+    {
+        SecurityManager securityManager = System.getSecurityManager();
+
+        if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+        {
+            ECParameterSpec curveSpec;
+
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+            }
+
+            if (parameter instanceof ECParameterSpec || parameter == null)
+            {
+                curveSpec = (ECParameterSpec)parameter;
+            }
+            else  // assume java.security.spec
+            {
+                curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+            }
+
+            if (curveSpec == null)
+            {
+                ecThreadSpec.remove();
+            }
+            else
+            {
+                ecThreadSpec.set(curveSpec);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_PERMISSION);
+            }
+
+            if (parameter instanceof ECParameterSpec || parameter == null)
+            {
+                ecImplicitCaParams = (ECParameterSpec)parameter;
+            }
+            else  // assume java.security.spec
+            {
+                ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+        {
+            DHParameterSpec dhSpec;
+
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_DH_LOCAL_PERMISSION);
+            }
+
+            if (parameter instanceof DHParameterSpec || parameter == null)
+            {
+                dhSpec = (DHParameterSpec)parameter;
+            }
+            else
+            {
+                throw new IllegalArgumentException("not a valid DHParameterSpec");
+            }
+
+            if (dhSpec == null)
+            {
+                dhThreadSpec.remove();
+            }
+            else
+            {
+                dhThreadSpec.set(dhSpec);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_DH_PERMISSION);
+            }
+
+            if (parameter instanceof DHParameterSpec || parameter == null)
+            {
+                dhDefaultParams = (DHParameterSpec)parameter;
+            }
+            else
+            {
+                throw new IllegalArgumentException("not a valid DHParameterSpec");
+            }
+        }
+    }
+
+    public ECParameterSpec getEcImplicitlyCa()
+    {
+        ECParameterSpec spec = (ECParameterSpec)ecThreadSpec.get();
+
+        if (spec != null)
+        {
+            return spec;
+        }
+
+        return ecImplicitCaParams;
+    }
+
+    public DHParameterSpec getDHDefaultParameters()
+    {
+        DHParameterSpec spec = (DHParameterSpec)dhThreadSpec.get();
+
+        if (spec != null)
+        {
+            return spec;
+        }
+
+        return dhDefaultParams;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
index f9dbe89..f8f6cb4 100644
--- a/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+++ b/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -6,6 +6,7 @@
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.PublicKey;
+import java.security.cert.CRLException;
 import java.security.cert.CertPath;
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.CertStore;
@@ -16,6 +17,7 @@
 import java.security.cert.PolicyQualifierInfo;
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
 import java.security.cert.X509CRLSelector;
 import java.security.cert.X509CertSelector;
 import java.security.cert.X509Certificate;
@@ -24,7 +26,6 @@
 import java.security.spec.DSAPublicKeySpec;
 import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
@@ -36,29 +37,29 @@
 
 import javax.security.auth.x500.X500Principal;
 
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.ASN1OctetString;
 import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DEREnumerated;
 import org.bouncycastle.asn1.DERGeneralizedTime;
 import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.CRLDistPoint;
-import org.bouncycastle.asn1.x509.CRLNumber;
 import org.bouncycastle.asn1.x509.CRLReason;
-import org.bouncycastle.asn1.x509.CertificateList;
 import org.bouncycastle.asn1.x509.DistributionPoint;
 import org.bouncycastle.asn1.x509.DistributionPointName;
 import org.bouncycastle.asn1.x509.GeneralName;
 import org.bouncycastle.asn1.x509.GeneralNames;
 import org.bouncycastle.asn1.x509.PolicyInformation;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Extension;
 import org.bouncycastle.asn1.x509.X509Extensions;
 // BEGIN android-removed
 // import org.bouncycastle.jce.X509LDAPCertStoreParameters;
@@ -95,16 +96,16 @@
     protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
 
     protected static final String ANY_POLICY = "2.5.29.32.0";
-    
-    protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
-    
-    /*
-     * key usage bits
-     */
-    protected static final int    KEY_CERT_SIGN = 5;
-    protected static final int    CRL_SIGN = 6;
 
-    protected static final String[] crlReasons = new String[] {
+    protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+    /*
+    * key usage bits
+    */
+    protected static final int KEY_CERT_SIGN = 5;
+    protected static final int CRL_SIGN = 6;
+
+    protected static final String[] crlReasons = new String[]{
         "unspecified",
         "keyCompromise",
         "cACompromise",
@@ -115,53 +116,47 @@
         "unknown",
         "removeFromCRL",
         "privilegeWithdrawn",
-        "aACompromise" };
-    
+        "aACompromise"};
+
     /**
      * Search the given Set of TrustAnchor's for one that is the
      * issuer of the given X509 certificate. Uses the default provider
      * for signature verification.
      *
-     * @param cert the X509 certificate
+     * @param cert         the X509 certificate
      * @param trustAnchors a Set of TrustAnchor's
-     *
      * @return the <code>TrustAnchor</code> object if found or
-     * <code>null</code> if not.
-     *
-     * @exception AnnotatedException
-     *                if a TrustAnchor was found but the signature verification
-     *                on the given certificate has thrown an exception.
+     *         <code>null</code> if not.
+     * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+     * on the given certificate has thrown an exception.
      */
     protected static TrustAnchor findTrustAnchor(
         X509Certificate cert,
-        Set             trustAnchors)
-            throws AnnotatedException
+        Set trustAnchors)
+        throws AnnotatedException
     {
         return findTrustAnchor(cert, trustAnchors, null);
     }
-    
+
     /**
      * Search the given Set of TrustAnchor's for one that is the
      * issuer of the given X509 certificate. Uses the specified
      * provider for signature verification, or the default provider
      * if null.
      *
-     * @param cert the X509 certificate
+     * @param cert         the X509 certificate
      * @param trustAnchors a Set of TrustAnchor's
-     * @param sigProvider the provider to use for signature verification
-     *
+     * @param sigProvider  the provider to use for signature verification
      * @return the <code>TrustAnchor</code> object if found or
-     * <code>null</code> if not.
-     *
-     * @exception AnnotatedException
-     *                if a TrustAnchor was found but the signature verification
-     *                on the given certificate has thrown an exception.
+     *         <code>null</code> if not.
+     * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+     * on the given certificate has thrown an exception.
      */
     protected static TrustAnchor findTrustAnchor(
         X509Certificate cert,
-        Set             trustAnchors,
-        String          sigProvider) 
-            throws AnnotatedException
+        Set trustAnchors,
+        String sigProvider)
+        throws AnnotatedException
     {
         TrustAnchor trust = null;
         PublicKey trustPublicKey = null;
@@ -182,7 +177,7 @@
         Iterator iter = trustAnchors.iterator();
         while (iter.hasNext() && trust == null)
         {
-            trust = (TrustAnchor) iter.next();
+            trust = (TrustAnchor)iter.next();
             if (trust.getTrustedCert() != null)
             {
                 if (certSelectX509.match(trust.getTrustedCert()))
@@ -195,7 +190,7 @@
                 }
             }
             else if (trust.getCAName() != null
-                    && trust.getCAPublicKey() != null)
+                && trust.getCAPublicKey() != null)
             {
                 try
                 {
@@ -229,6 +224,7 @@
                 {
                     invalidKeyEx = ex;
                     trust = null;
+                    trustPublicKey = null;
                 }
             }
         }
@@ -242,9 +238,9 @@
     }
 
     protected static void addAdditionalStoresFromAltNames(
-            X509Certificate cert,
-            ExtendedPKIXParameters pkixParams)
-            throws CertificateParsingException
+        X509Certificate cert,
+        ExtendedPKIXParameters pkixParams)
+        throws CertificateParsingException
     {
         // if in the IssuerAltName extension an URI
         // is given, add an additinal X.509 store
@@ -254,20 +250,22 @@
             while (it.hasNext())
             {
                 // look for URI
-                List list = (List) it.next();
+                List list = (List)it.next();
                 // BEGIN android-changed
                 if (list.get(0).equals(Integer.valueOf(GeneralName.uniformResourceIdentifier)))
                 // END android-changed
                 {
                     // found
-                    String temp = (String) list.get(1);
+                    String temp = (String)list.get(1);
                     CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
                 }
             }
         }
     }
+
     /**
      * Returns the issuer of an attribute certificate or certificate.
+     *
      * @param cert The attribute certificate or certificate.
      * @return The issuer as <code>X500Principal</code>.
      */
@@ -300,29 +298,26 @@
     {
         return cert.getSubjectX500Principal();
     }
-    
+
     protected static boolean isSelfIssued(X509Certificate cert)
     {
         return cert.getSubjectDN().equals(cert.getIssuerDN());
     }
-    
-    
+
+
     /**
      * Extract the value of the given extension, if it exists.
-     * 
-     * @param ext
-     *            The extension object.
-     * @param oid
-     *            The object identifier to obtain.
-     * @throws AnnotatedException
-     *             if the extension cannot be read.
+     *
+     * @param ext The extension object.
+     * @param oid The object identifier to obtain.
+     * @throws AnnotatedException if the extension cannot be read.
      */
-    protected static DERObject getExtensionValue(
-        java.security.cert.X509Extension    ext,
-        String                              oid)
+    protected static ASN1Primitive getExtensionValue(
+        java.security.cert.X509Extension ext,
+        String oid)
         throws AnnotatedException
     {
-        byte[]  bytes = ext.getExtensionValue(oid);
+        byte[] bytes = ext.getExtensionValue(oid);
         if (bytes == null)
         {
             return null;
@@ -330,11 +325,11 @@
 
         return getObject(oid, bytes);
     }
-    
-    private static DERObject getObject(
-            String oid,
-            byte[] ext)
-            throws AnnotatedException
+
+    private static ASN1Primitive getObject(
+        String oid,
+        byte[] ext)
+        throws AnnotatedException
     {
         try
         {
@@ -349,19 +344,19 @@
             throw new AnnotatedException("exception processing extension " + oid, e);
         }
     }
-    
+
     protected static X500Principal getIssuerPrincipal(X509CRL crl)
     {
         return crl.getIssuerX500Principal();
     }
-    
+
     protected static AlgorithmIdentifier getAlgorithmIdentifier(
         PublicKey key)
         throws CertPathValidatorException
     {
         try
         {
-            ASN1InputStream      aIn = new ASN1InputStream(key.getEncoded());
+            ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
 
             SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
 
@@ -372,55 +367,55 @@
             throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
         }
     }
-    
+
     // crl checking
 
 
     //
     // policy checking
     // 
-    
-    protected static final Set getQualifierSet(ASN1Sequence qualifiers) 
+
+    protected static final Set getQualifierSet(ASN1Sequence qualifiers)
         throws CertPathValidatorException
     {
-        Set             pq   = new HashSet();
-        
+        Set pq = new HashSet();
+
         if (qualifiers == null)
         {
             return pq;
         }
-        
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
-    
+
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
         Enumeration e = qualifiers.getObjects();
-    
+
         while (e.hasMoreElements())
         {
             try
             {
-                aOut.writeObject(e.nextElement());
-    
+                aOut.writeObject((ASN1Encodable)e.nextElement());
+
                 pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
             }
             catch (IOException ex)
             {
                 throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
             }
-    
+
             bOut.reset();
         }
-        
+
         return pq;
     }
-    
+
     protected static PKIXPolicyNode removePolicyNode(
-        PKIXPolicyNode  validPolicyTree,
-        List     []        policyNodes,
+        PKIXPolicyNode validPolicyTree,
+        List[] policyNodes,
         PKIXPolicyNode _node)
     {
         PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
-        
+
         if (validPolicyTree == null)
         {
             return null;
@@ -443,10 +438,10 @@
             return validPolicyTree;
         }
     }
-    
+
     private static void removePolicyNodeRecurse(
-        List     []        policyNodes,
-        PKIXPolicyNode  _node)
+        List[] policyNodes,
+        PKIXPolicyNode _node)
     {
         policyNodes[_node.getDepth()].remove(_node);
 
@@ -460,50 +455,50 @@
             }
         }
     }
-    
-    
+
+
     protected static boolean processCertD1i(
-        int                 index,
-        List     []            policyNodes,
+        int index,
+        List[] policyNodes,
         DERObjectIdentifier pOid,
-        Set                 pq)
+        Set pq)
     {
-        List       policyNodeVec = policyNodes[index - 1];
+        List policyNodeVec = policyNodes[index - 1];
 
         for (int j = 0; j < policyNodeVec.size(); j++)
         {
             PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
-            Set            expectedPolicies = node.getExpectedPolicies();
-            
+            Set expectedPolicies = node.getExpectedPolicies();
+
             if (expectedPolicies.contains(pOid.getId()))
             {
                 Set childExpectedPolicies = new HashSet();
                 childExpectedPolicies.add(pOid.getId());
-                
+
                 PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
-                                                           index,
-                                                           childExpectedPolicies,
-                                                           node,
-                                                           pq,
-                                                           pOid.getId(),
-                                                           false);
+                    index,
+                    childExpectedPolicies,
+                    node,
+                    pq,
+                    pOid.getId(),
+                    false);
                 node.addChild(child);
                 policyNodes[index].add(child);
-                
+
                 return true;
             }
         }
-        
+
         return false;
     }
 
     protected static void processCertD1ii(
-        int                 index,
-        List     []            policyNodes,
+        int index,
+        List[] policyNodes,
         DERObjectIdentifier _poid,
         Set _pq)
     {
-        List       policyNodeVec = policyNodes[index - 1];
+        List policyNodeVec = policyNodes[index - 1];
 
         for (int j = 0; j < policyNodeVec.size(); j++)
         {
@@ -513,28 +508,29 @@
             {
                 Set _childExpectedPolicies = new HashSet();
                 _childExpectedPolicies.add(_poid.getId());
-                
+
                 PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
-                                                           index,
-                                                           _childExpectedPolicies,
-                                                           _node,
-                                                           _pq,
-                                                           _poid.getId(),
-                                                           false);
+                    index,
+                    _childExpectedPolicies,
+                    _node,
+                    _pq,
+                    _poid.getId(),
+                    false);
                 _node.addChild(_child);
                 policyNodes[index].add(_child);
                 return;
             }
         }
     }
-    
+
     protected static void prepareNextCertB1(
-            int i,
-            List[] policyNodes,
-            String id_p,
-            Map m_idp,
-            X509Certificate cert
-            ) throws AnnotatedException,CertPathValidatorException
+        int i,
+        List[] policyNodes,
+        String id_p,
+        Map m_idp,
+        X509Certificate cert
+    )
+        throws AnnotatedException, CertPathValidatorException
     {
         boolean idp_found = false;
         Iterator nodes_i = policyNodes[i].iterator();
@@ -565,9 +561,7 @@
                     }
                     catch (Exception e)
                     {
-                        throw
-
-                        new AnnotatedException("Certificate policies cannot be decoded.", e);
+                        throw new AnnotatedException("Certificate policies cannot be decoded.", e);
                     }
                     Enumeration e = policies.getObjects();
                     while (e.hasMoreElements())
@@ -586,12 +580,12 @@
                         {
                             try
                             {
-                            pq = getQualifierSet(pinfo.getPolicyQualifiers());
+                                pq = getQualifierSet(pinfo.getPolicyQualifiers());
                             }
                             catch (CertPathValidatorException ex)
                             {
                                 throw new ExtCertPathValidatorException(
-                                        "Policy qualifier info set could not be built.", ex);
+                                    "Policy qualifier info set could not be built.", ex);
                             }
                             break;
                         }
@@ -606,9 +600,9 @@
                     if (ANY_POLICY.equals(p_node.getValidPolicy()))
                     {
                         PKIXPolicyNode c_node = new PKIXPolicyNode(
-                                new ArrayList(), i,
-                                (Set)m_idp.get(id_p),
-                                p_node, pq, id_p, ci);
+                            new ArrayList(), i,
+                            (Set)m_idp.get(id_p),
+                            p_node, pq, id_p, ci);
                         p_node.addChild(c_node);
                         policyNodes[i].add(c_node);
                     }
@@ -617,12 +611,12 @@
             }
         }
     }
-    
+
     protected static PKIXPolicyNode prepareNextCertB2(
-            int i,
-            List[] policyNodes,
-            String id_p,
-            PKIXPolicyNode validPolicyTree) 
+        int i,
+        List[] policyNodes,
+        String id_p,
+        PKIXPolicyNode validPolicyTree)
     {
         Iterator nodes_i = policyNodes[i].iterator();
         while (nodes_i.hasNext())
@@ -653,15 +647,15 @@
         }
         return validPolicyTree;
     }
-    
+
     protected static boolean isAnyPolicy(
         Set policySet)
     {
         return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
     }
-    
+
     protected static void addAdditionalStoreFromLocation(String location,
-        ExtendedPKIXParameters pkixParams)
+                                                         ExtendedPKIXParameters pkixParams)
     {
         if (pkixParams.isAdditionalLocationsEnabled())
         {
@@ -715,16 +709,16 @@
      * in the X509Store's that are matching the certSelect criteriums.
      *
      * @param certSelect a {@link Selector} object that will be used to select
-     *            the certificates
+     *                   the certificates
      * @param certStores a List containing only {@link X509Store} objects. These
-     *            are used to search for certificates.
-     *
+     *                   are used to search for certificates.
      * @return a Collection of all found {@link X509Certificate} or
      *         {@link org.bouncycastle.x509.X509AttributeCertificate} objects.
      *         May be empty but never <code>null</code>.
      */
     protected static Collection findCertificates(X509CertStoreSelector certSelect,
-        List certStores) throws AnnotatedException
+                                                 List certStores)
+        throws AnnotatedException
     {
         Set certs = new HashSet();
         Iterator iter = certStores.iterator();
@@ -742,10 +736,8 @@
                 }
                 catch (StoreException e)
                 {
-                    throw
-
-                    new AnnotatedException(
-                        "Problem while picking certificates from X.509 store.", e);
+                    throw new AnnotatedException(
+                            "Problem while picking certificates from X.509 store.", e);
                 }
             }
             else
@@ -770,7 +762,7 @@
     // BEGIN android-removed
     // protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
     //                                              List certStores)
-    // throws AnnotatedException
+    //     throws AnnotatedException
     // {
     //     Set certs = new HashSet();
     //     Iterator iter = certStores.iterator();
@@ -788,9 +780,7 @@
     //             }
     //             catch (StoreException e)
     //             {
-    //                 throw
-    //
-    //                     new AnnotatedException(
+    //                 throw new AnnotatedException(
     //                         "Problem while picking certificates from X.509 store.", e);
     //             }
     //         }
@@ -847,17 +837,17 @@
      * Add the CRL issuers from the cRLIssuer field of the distribution point or
      * from the certificate if not given to the issuer criterion of the
      * <code>selector</code>.
-     * <p>
+     * <p/>
      * The <code>issuerPrincipals</code> are a collection with a single
      * <code>X500Principal</code> for <code>X509Certificate</code>s. For
      * {@link X509AttributeCertificate}s the issuer may contain more than one
      * <code>X500Principal</code>.
      *
-     * @param dp The distribution point.
+     * @param dp               The distribution point.
      * @param issuerPrincipals The issuers of the certificate or attribute
-     *            certificate which contains the distribution point.
-     * @param selector The CRL selector.
-     * @param pkixParams The PKIX parameters containing the cert stores.
+     *                         certificate which contains the distribution point.
+     * @param selector         The CRL selector.
+     * @param pkixParams       The PKIX parameters containing the cert stores.
      * @throws AnnotatedException if an exception occurs while processing.
      * @throws ClassCastException if <code>issuerPrincipals</code> does not
      * contain only <code>X500Principal</code>s.
@@ -882,7 +872,7 @@
                     try
                     {
                         issuers.add(new X500Principal(genNames[j].getName()
-                            .getDERObject().getEncoded()));
+                            .toASN1Primitive().getEncoded()));
                     }
                     catch (IOException e)
                     {
@@ -905,7 +895,7 @@
                     "CRL issuer is omitted from distribution point but no distributionPoint field present.");
             }
             // add and check issuer principals
-            for (Iterator it=issuerPrincipals.iterator(); it.hasNext();)
+            for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
             {
                 issuers.add((X500Principal)it.next());
             }
@@ -924,7 +914,7 @@
 //                    throw new AnnotatedException(
 //                        "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
 //                }
-//                DEREncodable relName = dp.getDistributionPoint().getName();
+//                ASN1Encodable relName = dp.getDistributionPoint().getName();
 //                Iterator it = issuers.iterator();
 //                List issuersTemp = new ArrayList(issuers.size());
 //                while (it.hasNext())
@@ -944,7 +934,7 @@
 //                    ASN1EncodableVector v = new ASN1EncodableVector();
 //                    while (e.hasMoreElements())
 //                    {
-//                        v.add((DEREncodable) e.nextElement());
+//                        v.add((ASN1Encodable) e.nextElement());
 //                    }
 //                    v.add(relName);
 //                    issuersTemp.add(new X500Principal(new DERSequence(v)
@@ -970,82 +960,111 @@
     }
 
     private static BigInteger getSerialNumber(
-            Object cert)
+        Object cert)
     {
         if (cert instanceof X509Certificate)
         {
-            return ((X509Certificate) cert).getSerialNumber();
+            return ((X509Certificate)cert).getSerialNumber();
         }
         else
         {
-            return ((X509AttributeCertificate) cert).getSerialNumber();
+            return ((X509AttributeCertificate)cert).getSerialNumber();
         }
     }
-    
+
     protected static void getCertStatus(
-            Date validDate,
-            X509CRL crl,
-            Object cert,
-            CertStatus certStatus)
+        Date validDate,
+        X509CRL crl,
+        Object cert,
+        CertStatus certStatus)
         throws AnnotatedException
     {
-        // use BC X509CRLObject so that indirect CRLs are supported
-        X509CRLObject bcCRL = null;
+        X509CRLEntry crl_entry = null;
+
+        boolean isIndirect;
         try
         {
-            bcCRL = new X509CRLObject(new CertificateList((ASN1Sequence) ASN1Sequence.fromByteArray(crl.getEncoded())));
+            isIndirect = X509CRLObject.isIndirectCRL(crl);
         }
-        catch (Exception exception)
+        catch (CRLException exception)
         {
-            throw new AnnotatedException("Bouncy Castle X509CRLObject could not be created.", exception);
+            throw new AnnotatedException("Failed check for indirect CRL.", exception);
         }
-        // use BC X509CRLEntryObject, so that getCertificateIssuer() is
-        // supported.
-        X509CRLEntryObject crl_entry = (X509CRLEntryObject) bcCRL.getRevokedCertificate(getSerialNumber(cert));
-        if (crl_entry != null
-                && (getEncodedIssuerPrincipal(cert).equals(crl_entry.getCertificateIssuer()) || getEncodedIssuerPrincipal(cert)
-                        .equals(getIssuerPrincipal(crl))))
+
+        if (isIndirect)
         {
-            DEREnumerated reasonCode = null;
-            if (crl_entry.hasExtensions())
+            crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+            if (crl_entry == null)
             {
-                try
-                {
-                    reasonCode = DEREnumerated
-                        .getInstance(CertPathValidatorUtilities
-                            .getExtensionValue(crl_entry,
-                                X509Extensions.ReasonCode.getId()));
-                }
-                catch (Exception e)
-                {
-                    new AnnotatedException(
-                        "Reason code CRL entry extension could not be decoded.",
-                        e);
-                }
+                return;
             }
 
-            // for reason keyCompromise, caCompromise, aACompromise or
-            // unspecified
-            if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
-                || reasonCode == null
-                || reasonCode.getValue().intValue() == 0
-                || reasonCode.getValue().intValue() == 1
-                || reasonCode.getValue().intValue() == 2
-                || reasonCode.getValue().intValue() == 8)
-            {
+            X500Principal certIssuer = crl_entry.getCertificateIssuer();
 
-                // (i) or (j) (1)
-                if (reasonCode != null)
-                {
-                    certStatus.setCertStatus(reasonCode.getValue().intValue());
-                }
-                // (i) or (j) (2)
-                else
-                {
-                    certStatus.setCertStatus(CRLReason.unspecified);
-                }
-                certStatus.setRevocationDate(crl_entry.getRevocationDate());
+            if (certIssuer == null)
+            {
+                certIssuer = getIssuerPrincipal(crl);
             }
+
+            if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
+            {
+                return;
+            }
+        }
+        else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
+        {
+            return;  // not for our issuer, ignore
+        }
+        else
+        {
+            crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+            if (crl_entry == null)
+            {
+                return;
+            }
+        }
+
+        DEREnumerated reasonCode = null;
+        if (crl_entry.hasExtensions())
+        {
+            try
+            {
+                reasonCode = DEREnumerated
+                    .getInstance(CertPathValidatorUtilities
+                        .getExtensionValue(crl_entry,
+                            X509Extension.reasonCode.getId()));
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException(
+                    "Reason code CRL entry extension could not be decoded.",
+                    e);
+            }
+        }
+
+        // for reason keyCompromise, caCompromise, aACompromise or
+        // unspecified
+        if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+            || reasonCode == null
+            || reasonCode.getValue().intValue() == 0
+            || reasonCode.getValue().intValue() == 1
+            || reasonCode.getValue().intValue() == 2
+            || reasonCode.getValue().intValue() == 8)
+        {
+
+            // (i) or (j) (1)
+            if (reasonCode != null)
+            {
+                certStatus.setCertStatus(reasonCode.getValue().intValue());
+            }
+            // (i) or (j) (2)
+            else
+            {
+                certStatus.setCertStatus(CRLReason.unspecified);
+            }
+            certStatus.setRevocationDate(crl_entry.getRevocationDate());
         }
     }
 
@@ -1053,14 +1072,14 @@
      * Fetches delta CRLs according to RFC 3280 section 5.2.4.
      *
      * @param currentDate The date for which the delta CRLs must be valid.
-     * @param paramsPKIX The extended PKIX parameters.
+     * @param paramsPKIX  The extended PKIX parameters.
      * @param completeCRL The complete CRL the delta CRL is for.
      * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
      * @throws AnnotatedException if an exception occurs while picking the delta
-     *             CRLs.
+     * CRLs.
      */
     protected static Set getDeltaCRLs(Date currentDate,
-        ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
+                                      ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
         throws AnnotatedException
     {
 
@@ -1074,17 +1093,17 @@
         }
         catch (IOException e)
         {
-            new AnnotatedException("Cannot extract issuer from CRL.", e);
+            throw new AnnotatedException("Cannot extract issuer from CRL.", e);
         }
 
         BigInteger completeCRLNumber = null;
         try
         {
-            DERObject derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
-                    CRL_NUMBER);
+            ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+                CRL_NUMBER);
             if (derObject != null)
             {
-                completeCRLNumber = CRLNumber.getInstance(derObject).getPositiveValue();
+                completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
             }
         }
         catch (Exception e)
@@ -1122,10 +1141,10 @@
 
         Set result = new HashSet();
 
-        for (Iterator it = temp.iterator(); it.hasNext();)
+        for (Iterator it = temp.iterator(); it.hasNext(); )
         {
             X509CRL crl = (X509CRL)it.next();
-            
+
             if (isDeltaCRL(crl))
             {
                 result.add(crl);
@@ -1139,25 +1158,30 @@
     {
         Set critical = crl.getCriticalExtensionOIDs();
 
+        if (critical == null)
+        {
+            return false;
+        }
+
         return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
     }
 
     /**
      * Fetches complete CRLs according to RFC 3280.
      *
-     * @param dp The distribution point for which the complete CRL
-     * @param cert The <code>X509Certificate</code> or
-     *            {@link org.bouncycastle.x509.X509AttributeCertificate} for
-     *            which the CRL should be searched.
+     * @param dp          The distribution point for which the complete CRL
+     * @param cert        The <code>X509Certificate</code> or
+     *                    {@link org.bouncycastle.x509.X509AttributeCertificate} for
+     *                    which the CRL should be searched.
      * @param currentDate The date for which the delta CRLs must be valid.
-     * @param paramsPKIX The extended PKIX parameters.
+     * @param paramsPKIX  The extended PKIX parameters.
      * @return A <code>Set</code> of <code>X509CRL</code>s with complete
      *         CRLs.
      * @throws AnnotatedException if an exception occurs while picking the CRLs
-     *             or no CRLs are found.
+     * or no CRLs are found.
      */
     protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
-        Date currentDate, ExtendedPKIXParameters paramsPKIX)
+                                         Date currentDate, ExtendedPKIXParameters paramsPKIX)
         throws AnnotatedException
     {
         X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
@@ -1177,7 +1201,7 @@
         }
         catch (AnnotatedException e)
         {
-            new AnnotatedException(
+            throw new AnnotatedException(
                 "Could not get issuer information from distribution point.", e);
         }
         if (cert instanceof X509Certificate)
@@ -1190,7 +1214,6 @@
         }
 
 
-
         crlselect.setCompleteCRLEnabled(true);
 
         Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
@@ -1235,7 +1258,7 @@
                         byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
                         if (extBytes != null)
                         {
-                            dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Object.fromByteArray(extBytes));
+                            dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes));
                         }
                     }
                     catch (IOException e)
@@ -1261,12 +1284,12 @@
                                 e);
                         }
                     }
-                    return ((X509Certificate) certPath.getCertificates().get(
+                    return ((X509Certificate)certPath.getCertificates().get(
                         index - 1)).getNotBefore();
                 }
                 else
                 {
-                    return ((X509Certificate) certPath.getCertificates().get(
+                    return ((X509Certificate)certPath.getCertificates().get(
                         index - 1)).getNotBefore();
                 }
             }
@@ -1290,10 +1313,10 @@
      * returns the public key. If the DSA key already contains DSA parameters
      * the key is also only returned.
      * </p>
-     * 
+     *
      * @param certs The certification path.
      * @param index The index of the certificate which contains the public key
-     *            which should be extended with DSA parameters.
+     *              which should be extended with DSA parameters.
      * @return The public key of the certificate in list position
      *         <code>index</code> extended with DSA parameters if applicable.
      * @throws AnnotatedException if DSA parameters cannot be inherited.
@@ -1301,13 +1324,13 @@
     protected static PublicKey getNextWorkingKey(List certs, int index)
         throws CertPathValidatorException
     {
-        Certificate cert = (Certificate) certs.get(index);
+        Certificate cert = (Certificate)certs.get(index);
         PublicKey pubKey = cert.getPublicKey();
         if (!(pubKey instanceof DSAPublicKey))
         {
             return pubKey;
         }
-        DSAPublicKey dsaPubKey = (DSAPublicKey) pubKey;
+        DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
         if (dsaPubKey.getParams() != null)
         {
             return dsaPubKey;
@@ -1321,7 +1344,7 @@
                 throw new CertPathValidatorException(
                     "DSA parameters cannot be inherited from previous certificate.");
             }
-            DSAPublicKey prevDSAPubKey = (DSAPublicKey) pubKey;
+            DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
             if (prevDSAPubKey.getParams() == null)
             {
                 continue;
@@ -1341,23 +1364,20 @@
         }
         throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
     }
-    
+
     /**
      * Find the issuer certificates of a given certificate.
-     * 
-     * @param cert
-     *            The certificate for which an issuer should be found.
+     *
+     * @param cert       The certificate for which an issuer should be found.
      * @param pkixParams
      * @return A <code>Collection</code> object containing the issuer
      *         <code>X509Certificate</code>s. Never <code>null</code>.
-     * 
-     * @exception AnnotatedException
-     *                if an error occurs.
+     * @throws AnnotatedException if an error occurs.
      */
     protected static Collection findIssuerCerts(
         X509Certificate cert,
         ExtendedPKIXBuilderParameters pkixParams)
-            throws AnnotatedException
+        throws AnnotatedException
     {
         X509CertStoreSelector certSelect = new X509CertStoreSelector();
         Set certs = new HashSet();
@@ -1368,7 +1388,7 @@
         catch (IOException ex)
         {
             throw new AnnotatedException(
-                    "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+                "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
         }
 
         Iterator iter;
@@ -1391,7 +1411,7 @@
         X509Certificate issuer = null;
         while (iter.hasNext())
         {
-            issuer = (X509Certificate) iter.next();
+            issuer = (X509Certificate)iter.next();
             // issuer cannot be verified because possible DSA inheritance
             // parameters are missing
             certs.add(issuer);
@@ -1400,8 +1420,8 @@
     }
 
     protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
-        String sigProvider)
-            throws GeneralSecurityException
+                                                String sigProvider)
+        throws GeneralSecurityException
     {
         if (sigProvider == null)
         {
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java b/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
index 1b48aec..2205a26 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
@@ -11,6 +11,7 @@
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.NoSuchPaddingException;
 import javax.crypto.SecretKey;
@@ -29,7 +30,6 @@
 import org.bouncycastle.crypto.InvalidCipherTextException;
 import org.bouncycastle.crypto.engines.AESFastEngine;
 import org.bouncycastle.crypto.engines.DESEngine;
-import org.bouncycastle.crypto.engines.DESedeEngine;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.engines.GOST28147Engine;
 // END android-removed
@@ -44,7 +44,9 @@
 // import org.bouncycastle.crypto.modes.EAXBlockCipher;
 // END android-removed
 import org.bouncycastle.crypto.modes.GCMBlockCipher;
-import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+// END android-removed
 import org.bouncycastle.crypto.modes.OFBBlockCipher;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
@@ -65,11 +67,17 @@
 // import org.bouncycastle.crypto.params.ParametersWithSBox;
 // import org.bouncycastle.crypto.params.RC2Parameters;
 // import org.bouncycastle.crypto.params.RC5Parameters;
+// END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
+// 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 JCEBlockCipher extends WrapCipherSpi
+public class JCEBlockCipher
+    extends CipherSpi
     implements PBE
 {
     //
@@ -101,6 +109,8 @@
     
     private String                  modeName = null;
 
+    private AlgorithmParameters engineParams;
+
     protected JCEBlockCipher(
         BlockCipher engine)
     {
@@ -272,12 +282,14 @@
             cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
                         new SICBlockCipher(baseEngine)));
         }
-        else if (modeName.startsWith("GOFB"))
-        {
-            ivLength = baseEngine.getBlockSize();
-            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
-                        new GOFBBlockCipher(baseEngine)));
-        }
+        // BEGIN android-removed
+        // else if (modeName.startsWith("GOFB"))
+        // {
+        //     ivLength = baseEngine.getBlockSize();
+        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+        //                 new GOFBBlockCipher(baseEngine)));
+        // }
+        // END android-removed
         else if (modeName.startsWith("CTS"))
         {
             ivLength = baseEngine.getBlockSize();
@@ -396,9 +408,9 @@
         //
         // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
         //
-        if (key instanceof JCEPBEKey)
+        if (key instanceof BCPBEKey)
         {
-            JCEPBEKey   k = (JCEPBEKey)key;
+            BCPBEKey k = (BCPBEKey)key;
             
             if (k.getOID() != null)
             {
@@ -444,8 +456,16 @@
                     throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
                 }
 
-                param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
-                ivParam = (ParametersWithIV)param;
+                if (key instanceof RepeatedSecretKeySpec)
+                {
+                    param = new ParametersWithIV(null, p.getIV());
+                    ivParam = (ParametersWithIV)param;
+                }
+                else
+                {
+                    param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+                    ivParam = (ParametersWithIV)param;
+                }
             }
             else
             {
@@ -857,7 +877,7 @@
             super(new CBCBlockCipher(new RC2Engine()));
         }
     }
-    
+
     /**
      * PBEWithSHA1AndDES
      */
@@ -882,30 +902,8 @@
         }
     }
 
-    /**
-     * PBEWithSHAAnd3-KeyTripleDES-CBC
-     */
-    static public class PBEWithSHAAndDES3Key
-        extends JCEBlockCipher
-    {
-        public PBEWithSHAAndDES3Key()
-        {
-            super(new CBCBlockCipher(new DESedeEngine()));
-        }
-    }
 
-    /**
-     * PBEWithSHAAnd2-KeyTripleDES-CBC
-     */
-    static public class PBEWithSHAAndDES2Key
-        extends JCEBlockCipher
-    {
-        public PBEWithSHAAndDES2Key()
-        {
-            super(new CBCBlockCipher(new DESedeEngine()));
-        }
-    }
-    
+
     /**
      * PBEWithSHAAnd128BitRC2-CBC
      */
@@ -929,7 +927,7 @@
             super(new CBCBlockCipher(new RC2Engine()));
         }
     }
-    
+
     /**
      * PBEWithSHAAndTwofish-CBC
      */
@@ -941,7 +939,7 @@
             super(new CBCBlockCipher(new TwofishEngine()));
         }
     }
-    
+
     /**
      * PBEWithAES-CBC
      */
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
index fc38481..46295c5 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
@@ -10,8 +10,10 @@
 import javax.crypto.spec.DHParameterSpec;
 import javax.crypto.spec.DHPrivateKeySpec;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.pkcs.DHParameter;
@@ -21,6 +23,7 @@
 import org.bouncycastle.asn1.x9.DHDomainParameters;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
 
 public class JCEDHPrivateKey
@@ -55,17 +58,18 @@
 
     JCEDHPrivateKey(
         PrivateKeyInfo  info)
+        throws IOException
     {
         ASN1Sequence    seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
-        DERInteger      derX = (DERInteger)info.getPrivateKey();
-        DERObjectIdentifier id = info.getAlgorithmId().getObjectId();
+        DERInteger      derX = DERInteger.getInstance(info.parsePrivateKey());
+        DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm();
 
         this.info = info;
         this.x = derX.getValue();
 
         if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
         {
-            DHParameter params = new DHParameter(seq);
+            DHParameter params = DHParameter.getInstance(seq);
 
             if (params.getL() != null)
             {
@@ -118,14 +122,21 @@
      */
     public byte[] getEncoded()
     {
-        if (info != null)
+        try
         {
-            return info.getDEREncoded();
-        }
-        
-        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(getX()));
+            if (info != null)
+            {
+                return info.getEncoded(ASN1Encoding.DER);
+            }
 
-        return info.getDEREncoded();
+            PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(getX()));
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
     }
 
     public DHParameterSpec getParams()
@@ -158,13 +169,13 @@
     }
 
     public void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
     {
         attrCarrier.setBagAttribute(oid, attribute);
     }
 
-    public DEREncodable getBagAttribute(
+    public ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid)
     {
         return attrCarrier.getBagAttribute(oid);
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
index 942e3bf..6ff1e08 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
@@ -19,6 +19,7 @@
 import org.bouncycastle.asn1.x9.DHDomainParameters;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
 
 public class JCEDHPublicKey
     implements DHPublicKey
@@ -66,7 +67,7 @@
         DERInteger              derY;
         try
         {
-            derY = (DERInteger)info.getPublicKey();
+            derY = (DERInteger)info.parsePublicKey();
         }
         catch (IOException e)
         {
@@ -76,12 +77,12 @@
         this.y = derY.getValue();
 
         ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
-        DERObjectIdentifier id = info.getAlgorithmId().getObjectId();
+        DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm();
 
         // we need the PKCS check to handle older keys marked with the X9 oid.
         if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
         {
-            DHParameter             params = new DHParameter(seq);
+            DHParameter             params = DHParameter.getInstance(seq);
 
             if (params.getL() != null)
             {
@@ -118,12 +119,10 @@
     {
         if (info != null)
         {
-            return info.getDEREncoded();
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
         }
 
-        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(y));
-
-        return info.getDEREncoded();
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(y));
     }
 
     public DHParameterSpec getParams()
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
index 3b3f318..97455bd 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
@@ -11,13 +11,14 @@
 import java.security.spec.EllipticCurve;
 import java.util.Enumeration;
 
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
 // BEGIN android-removed
@@ -32,10 +33,11 @@
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.ECDomainParameters;
 import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.ECUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
 import org.bouncycastle.jce.interfaces.ECPointEncoder;
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
 import org.bouncycastle.jce.spec.ECNamedCurveSpec;
 import org.bouncycastle.math.ec.ECCurve;
 
@@ -188,17 +190,19 @@
 
     JCEECPrivateKey(
         PrivateKeyInfo      info)
+        throws IOException
     {
         populateFromPrivKeyInfo(info);
     }
 
     private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+        throws IOException
     {
-        X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
+        X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters());
 
         if (params.isNamedCurve())
         {
-            DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
             X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
 
             // BEGIN android-removed
@@ -237,7 +241,7 @@
         }
         else
         {
-            X9ECParameters      ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
+            X9ECParameters      ecP = X9ECParameters.getInstance(params.getParameters());
             EllipticCurve       ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
 
             this.ecSpec = new ECParameterSpec(
@@ -249,15 +253,16 @@
                 ecP.getH().intValue());
         }
 
-        if (info.getPrivateKey() instanceof DERInteger)
+        ASN1Encodable privKey = info.parsePrivateKey();
+        if (privKey instanceof DERInteger)
         {
-            DERInteger          derD = (DERInteger)info.getPrivateKey();
+            DERInteger          derD = DERInteger.getInstance(privKey);
 
             this.d = derD.getValue();
         }
         else
         {
-            ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)info.getPrivateKey());
+            ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)privKey);
 
             this.d = ec.getKey();
             this.publicKey = ec.getPublicKey();
@@ -328,19 +333,26 @@
             keyStructure = new ECPrivateKeyStructure(this.getS(), params);
         }
 
-        // BEGIN android-removed
-        // if (algorithm.equals("ECGOST3410"))
-        // {
-        //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), keyStructure.getDERObject());
-        // }
-        // else
-        // END android-removed
+        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.getDERObject()), keyStructure.getDERObject());
+                info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+            }
+
+            return info.getEncoded(ASN1Encoding.DER);
         }
-
-        return info.getDEREncoded();
+        catch (IOException e)
+        {
+            return null;
+        }
     }
 
     public ECParameterSpec getParams()
@@ -365,7 +377,7 @@
             return EC5Util.convertSpec(ecSpec, withCompression);
         }
 
-        return ProviderUtil.getEcImplicitlyCa();
+        return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
     }
 
     public BigInteger getS()
@@ -379,13 +391,13 @@
     }
     
     public void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
     {
         attrCarrier.setBagAttribute(oid, attribute);
     }
 
-    public DEREncodable getBagAttribute(
+    public ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid)
     {
         return attrCarrier.getBagAttribute(oid);
@@ -434,7 +446,7 @@
     {
         try
         {
-            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(pub.getEncoded()));
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
 
             return info.getPublicKeyData();
         }
@@ -450,7 +462,7 @@
     {
         byte[] enc = (byte[])in.readObject();
 
-        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(enc)));
+        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
 
         this.algorithm = (String)in.readObject();
         this.withCompression = in.readBoolean();
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
index 00277ac..d1462d5 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
@@ -11,13 +11,12 @@
 import java.security.spec.EllipticCurve;
 
 import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
 // BEGIN android-removed
@@ -33,12 +32,13 @@
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.ECDomainParameters;
 import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.ECUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
 // BEGIN android-removed
 // import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
 // END android-removed
 import org.bouncycastle.jce.interfaces.ECPointEncoder;
-import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
 // BEGIN android-removed
 // import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
 // END android-removed
@@ -96,7 +96,7 @@
         {
             if (q.getCurve() == null)
             {
-                org.bouncycastle.jce.spec.ECParameterSpec s = ProviderUtil.getEcImplicitlyCa();
+                org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
 
                 q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
             }               
@@ -198,7 +198,7 @@
         //
         //     try
         //     {
-        //         key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
+        //         key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes());
         //     }
         //     catch (IOException ex)
         //     {
@@ -240,13 +240,13 @@
         // else
         // END android-removed
         {
-            X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
+            X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters());
             ECCurve                 curve;
             EllipticCurve           ellipticCurve;
 
             if (params.isNamedCurve())
             {
-                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
                 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
 
                 curve = ecP.getCurve();
@@ -264,11 +264,11 @@
             else if (params.isImplicitlyCA())
             {
                 ecSpec = null;
-                curve = ProviderUtil.getEcImplicitlyCa().getCurve();
+                curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
             }
             else
             {
-                X9ECParameters          ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
+                X9ECParameters          ecP = X9ECParameters.getInstance(params.getParameters());
 
                 curve = ecP.getCurve();
                 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
@@ -298,7 +298,7 @@
                 {
                     try
                     {
-                        key = (ASN1OctetString) ASN1Object.fromByteArray(data);
+                        key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
                     }
                     catch (IOException ex)
                     {
@@ -364,17 +364,17 @@
         //     extractBytes(encKey, 0, bX);
         //     extractBytes(encKey, 32, bY);
         //
-        //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
+        //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
         // }
         // else
         // END android-removed
         {
             if (ecSpec instanceof ECNamedCurveSpec)
             {
-                DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+                ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
                 if (curveOid == null)
                 {
-                    curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+                    curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
                 }
                 params = new X962Parameters(curveOid);
             }
@@ -398,12 +398,12 @@
 
             ECCurve curve = this.engineGetQ().getCurve();
             ASN1OctetString p = (ASN1OctetString)
-                new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).getDERObject();
+                new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive();
 
-            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), p.getOctets());
+            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
         }
 
-        return info.getDEREncoded();
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
     }
 
     private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
@@ -471,7 +471,7 @@
             return EC5Util.convertSpec(ecSpec, withCompression);
         }
 
-        return ProviderUtil.getEcImplicitlyCa();
+        return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
     }
 
     public String toString()
@@ -515,7 +515,7 @@
     {
         byte[] enc = (byte[])in.readObject();
 
-        populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(enc)));
+        populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
 
         this.algorithm = (String)in.readObject();
         this.withCompression = in.readBoolean();
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java b/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
deleted file mode 100644
index 6373557..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
+++ /dev/null
@@ -1,269 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidParameterException;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-
-import javax.crypto.KeyGeneratorSpi;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.KeyGenerationParameters;
-import org.bouncycastle.crypto.generators.DESKeyGenerator;
-
-public class JCEKeyGenerator
-    extends KeyGeneratorSpi
-{
-    protected String                algName;
-    protected int                   keySize;
-    protected int                   defaultKeySize;
-    protected CipherKeyGenerator    engine;
-
-    protected boolean               uninitialised = true;
-
-    protected JCEKeyGenerator(
-        String              algName,
-        int                 defaultKeySize,
-        CipherKeyGenerator  engine)
-    {
-        this.algName = algName;
-        this.keySize = this.defaultKeySize = defaultKeySize;
-        this.engine = engine;
-    }
-
-    protected void engineInit(
-        AlgorithmParameterSpec  params,
-        SecureRandom            random)
-    throws InvalidAlgorithmParameterException
-    {
-        throw new InvalidAlgorithmParameterException("Not Implemented");
-    }
-
-    protected void engineInit(
-        SecureRandom    random)
-    {
-        if (random != null)
-        {
-            engine.init(new KeyGenerationParameters(random, defaultKeySize));
-            uninitialised = false;
-        }
-    }
-
-    protected void engineInit(
-        int             keySize,
-        SecureRandom    random)
-    {
-        try
-        {
-            // BEGIN android-added
-            if (random == null) {
-                random = new SecureRandom();
-            }
-            // END android-added
-            engine.init(new KeyGenerationParameters(random, keySize));
-            uninitialised = false;
-        }
-        catch (IllegalArgumentException e)
-        {
-            throw new InvalidParameterException(e.getMessage());
-        }
-    }
-
-    protected SecretKey engineGenerateKey()
-    {
-        if (uninitialised)
-        {
-            engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
-            uninitialised = false;
-        }
-
-        return new SecretKeySpec(engine.generateKey(), algName);
-    }
-
-    /**
-     * the generators that are defined directly off us.
-     */
-
-    /**
-     * DES
-     */
-    public static class DES
-        extends JCEKeyGenerator
-    {
-        public DES()
-        {
-            super("DES", 64, new DESKeyGenerator());
-        }
-    }
-
-    // BEGIN android-removed
-    // /**
-    //  * RC2
-    //  */
-    // public static class RC2
-    //     extends JCEKeyGenerator
-    // {
-    //     public RC2()
-    //     {
-    //         super("RC2", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * GOST28147
-    //  */
-    // public static class GOST28147
-    //     extends JCEKeyGenerator
-    // {
-    //     public GOST28147()
-    //     {
-    //         super("GOST28147", 256, new CipherKeyGenerator());
-    //     }
-    // }
-    // END android-removed
-
-    // HMAC Related secret keys..
-  
-    // BEGIN android-removed
-    // /**
-    //  * MD2HMAC
-    //  */
-    // public static class MD2HMAC
-    //     extends JCEKeyGenerator
-    // {
-    //     public MD2HMAC()
-    //     {
-    //         super("HMACMD2", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    //
-    // /**
-    //  * MD4HMAC
-    //  */
-    // public static class MD4HMAC
-    //     extends JCEKeyGenerator
-    // {
-    //     public MD4HMAC()
-    //     {
-    //         super("HMACMD4", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    // END android-removed
-
-    /**
-     * MD5HMAC
-     */
-    public static class MD5HMAC
-        extends JCEKeyGenerator
-    {
-        public MD5HMAC()
-        {
-            super("HMACMD5", 128, new CipherKeyGenerator());
-        }
-    }
-
-
-    // /**
-    //  * RIPE128HMAC
-    //  */
-    // public static class RIPEMD128HMAC
-    //     extends JCEKeyGenerator
-    // {
-    //     public RIPEMD128HMAC()
-    //     {
-    //         super("HMACRIPEMD128", 128, new CipherKeyGenerator());
-    //     }
-    // }
-
-    // /**
-    //  * RIPE160HMAC
-    //  */
-    // public static class RIPEMD160HMAC
-    //     extends JCEKeyGenerator
-    // {
-    //     public RIPEMD160HMAC()
-    //     {
-    //         super("HMACRIPEMD160", 160, new CipherKeyGenerator());
-    //     }
-    // }
-
-
-    /**
-     * HMACSHA1
-     */
-    public static class HMACSHA1
-        extends JCEKeyGenerator
-    {
-        public HMACSHA1()
-        {
-            super("HMACSHA1", 160, new CipherKeyGenerator());
-        }
-    }
-
-    // BEGIN android-removed
-    // /**
-    //  * HMACSHA224
-    //  */
-    // public static class HMACSHA224
-    //     extends JCEKeyGenerator
-    // {
-    //     public HMACSHA224()
-    //     {
-    //         super("HMACSHA224", 224, new CipherKeyGenerator());
-    //     }
-    // }
-    // END android-removed
-    
-    /**
-     * HMACSHA256
-     */
-    public static class HMACSHA256
-        extends JCEKeyGenerator
-    {
-        public HMACSHA256()
-        {
-            super("HMACSHA256", 256, new CipherKeyGenerator());
-        }
-    }
-    
-    /**
-     * HMACSHA384
-     */
-    public static class HMACSHA384
-        extends JCEKeyGenerator
-    {
-        public HMACSHA384()
-        {
-            super("HMACSHA384", 384, new CipherKeyGenerator());
-        }
-    }
-    
-    /**
-     * HMACSHA512
-     */
-    public static class HMACSHA512
-        extends JCEKeyGenerator
-    {
-        public HMACSHA512()
-        {
-            super("HMACSHA512", 512, new CipherKeyGenerator());
-        }
-    }
-    
-    // BEGIN android-removed
-    // /**
-    //  * HMACTIGER
-    //  */
-    // public static class HMACTIGER
-    //     extends JCEKeyGenerator
-    // {
-    //     public HMACTIGER()
-    //     {
-    //         super("HMACTIGER", 192, new CipherKeyGenerator());
-    //     }
-    // }
-    // END android-removed
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEMac.java b/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
index cf876f5..8d6249d 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
@@ -14,22 +14,19 @@
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.MD2Digest;
 // import org.bouncycastle.crypto.digests.MD4Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.MD5Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD5Digest;
 // import org.bouncycastle.crypto.digests.RIPEMD128Digest;
 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.SHA1Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
 // import org.bouncycastle.crypto.digests.SHA224Digest;
-// END android-removed
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
 // import org.bouncycastle.crypto.digests.TigerDigest;
 // END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.OpenSSLDigest;
+// END android-added
 import org.bouncycastle.crypto.engines.DESEngine;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.engines.RC2Engine;
@@ -37,7 +34,6 @@
 import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
-// import org.bouncycastle.crypto.macs.GOST28147Mac;
 // END android-removed
 import org.bouncycastle.crypto.macs.HMac;
 // BEGIN android-removed
@@ -47,6 +43,8 @@
 import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
 
 public class JCEMac
     extends MacSpi implements PBE
@@ -87,9 +85,9 @@
             throw new InvalidKeyException("key is null");
         }
         
-        if (key instanceof JCEPBEKey)
+        if (key instanceof BCPBEKey)
         {
-            JCEPBEKey   k = (JCEPBEKey)key;
+            BCPBEKey k = (BCPBEKey)key;
             
             if (k.getParam() != null)
             {
@@ -171,6 +169,18 @@
     // }
     //
     // /**
+    //  * DES 64 bit MAC
+    //  */
+    // public static class DES64
+    //     extends JCEMac
+    // {
+    //     public DES64()
+    //     {
+    //         super(new CBCBlockCipherMac(new DESEngine(), 64));
+    //     }
+    // }
+    //
+    // /**
     //  * RC2
     //  */
     // public static class RC2
@@ -182,17 +192,6 @@
     //     }
     // }
     //
-    // /**
-    //  * GOST28147
-    //  */
-    // public static class GOST28147
-    //     extends JCEMac
-    // {
-    //     public GOST28147()
-    //     {
-    //         super(new GOST28147Mac());
-    //     }
-    // }
     //
     //
     //
@@ -211,14 +210,7 @@
     // /**
     //  * RC2CFB8
     //  */
-    // public static class RC2CFB8
-    //     extends JCEMac
-    // {
-    //     public RC2CFB8()
-    //     {
-    //         super(new CFBBlockCipherMac(new RC2Engine()));
-    //     }
-    // }
+    //
     //
     // /**
     //  * DES9797Alg3with7816-4Padding
@@ -277,10 +269,12 @@
     {
         public MD5()
         {
-            super(new HMac(new MD5Digest()));
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.MD5()));
+            // END android-changed
         }
     }
-    
+
     /**
      * SHA1 HMac
      */
@@ -289,10 +283,12 @@
     {
         public SHA1()
         {
-            super(new HMac(new SHA1Digest()));
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA1()));
+            // END android-changed
         }
     }
-    
+
     // BEGIN android-removed
     // /**
     //  * SHA-224 HMac
@@ -315,10 +311,12 @@
     {
         public SHA256()
         {
-            super(new HMac(new SHA256Digest()));
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA256()));
+            // END android-changed
         }
     }
-    
+
     /**
      * SHA-384 HMac
      */
@@ -327,10 +325,12 @@
     {
         public SHA384()
         {
-            super(new HMac(new SHA384Digest()));
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA384()));
+            // END android-changed
         }
     }
-    
+
     // BEGIN android-removed
     // public static class OldSHA384
     //     extends JCEMac
@@ -350,9 +350,12 @@
     {
         public SHA512()
         {
-            super(new HMac(new SHA512Digest()));
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA512()));
+            // END android-changed
         }
     }
+
     
     // BEGIN android-removed
     // /**
@@ -421,7 +424,7 @@
     //     }
     // }
     // END android-removed
-    
+
     /**
      * PBEWithHmacSHA
      */
@@ -430,10 +433,12 @@
     {
         public PBEWithSHA()
         {
-            super(new HMac(new SHA1Digest()), PKCS12, SHA1, 160);
+            // BEGIN android-changed
+            super(new HMac(new OpenSSLDigest.SHA1()), PKCS12, SHA1, 160);
+            // END android-changed
         }
     }
-    
+
     // BEGIN android-removed
     //  /**
     //   * PBEWithHmacTiger
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java b/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
index c7e2794..c4c5b61 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
@@ -1,17 +1,18 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
-
+import java.io.IOException;
 import java.math.BigInteger;
 import java.security.interfaces.RSAPrivateCrtKey;
 import java.security.spec.RSAPrivateCrtKeySpec;
 
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
 /**
  * A provider representation for a RSA private key, with CRT factors included.
  */
@@ -87,15 +88,16 @@
      */
     JCERSAPrivateCrtKey(
         PrivateKeyInfo  info)
+        throws IOException
     {
-        this(new RSAPrivateKeyStructure((ASN1Sequence)info.getPrivateKey()));
+        this(org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(info.parsePrivateKey()));
     }
 
     /**
      * construct an RSA key from a ASN.1 RSA private key object.
      */
     JCERSAPrivateCrtKey(
-        RSAPrivateKeyStructure  key)
+        RSAPrivateKey  key)
     {
         this.modulus = key.getModulus();
         this.publicExponent = key.getPublicExponent();
@@ -126,10 +128,8 @@
     public byte[] getEncoded()
     {
         // BEGIN android-changed
-        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKeyStructure(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()).getDERObject());
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
         // END android-changed
-
-        return info.getDEREncoded();
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
index bbead9f..6277415 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
@@ -1,15 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
-import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -18,6 +8,17 @@
 import java.security.spec.RSAPrivateKeySpec;
 import java.util.Enumeration;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
 public class JCERSAPrivateKey
     implements RSAPrivateKey, PKCS12BagAttributeCarrier
 {
@@ -28,7 +29,7 @@
     protected BigInteger modulus;
     protected BigInteger privateExponent;
 
-    private PKCS12BagAttributeCarrierImpl   attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
 
     protected JCERSAPrivateKey()
     {
@@ -78,10 +79,8 @@
     public byte[] getEncoded()
     {
         // BEGIN android-changed
-        PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKeyStructure(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO).getDERObject());
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
         // END android-changed
-
-        return info.getDEREncoded();
     }
 
     public boolean equals(Object o)
@@ -108,13 +107,13 @@
     }
 
     public void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
     {
         attrCarrier.setBagAttribute(oid, attribute);
     }
 
-    public DEREncodable getBagAttribute(
+    public ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid)
     {
         return attrCarrier.getBagAttribute(oid);
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
index ea601ed..8d74351 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
@@ -1,5 +1,10 @@
 package org.bouncycastle.jce.provider;
 
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -7,11 +12,7 @@
 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.crypto.params.RSAKeyParameters;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.RSAPublicKeySpec;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
 
 public class JCERSAPublicKey
     implements RSAPublicKey
@@ -47,7 +48,7 @@
     {
         try
         {
-            RSAPublicKeyStructure   pubKey = new RSAPublicKeyStructure((ASN1Sequence)info.getPublicKey());
+            RSAPublicKeyStructure   pubKey = new RSAPublicKeyStructure((ASN1Sequence)info.parsePublicKey());
 
             this.modulus = pubKey.getModulus();
             this.publicExponent = pubKey.getPublicExponent();
@@ -91,10 +92,8 @@
     public byte[] getEncoded()
     {
         // BEGIN android-changed
-        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()).getDERObject());
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()));
         // END android-changed
-
-        return info.getDEREncoded();
     }
 
     public int hashCode()
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
index 51f8e38..7d70734 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
@@ -17,6 +17,8 @@
 import org.bouncycastle.crypto.params.DESParameters;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
 
 public class JCESecretKeyFactory
     extends SecretKeyFactorySpi
@@ -140,7 +142,7 @@
                 
                 if (pbeSpec.getSalt() == null)
                 {
-                    return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+                    return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
                 }
                 
                 if (forCipher)
@@ -152,7 +154,7 @@
                     param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
                 }
                 
-                return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
             }
             
             throw new InvalidKeySpecException("Invalid KeySpec");
@@ -197,7 +199,7 @@
                 
                 if (pbeSpec.getSalt() == null)
                 {
-                    return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+                    return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
                 }
                 
                 if (forCipher)
@@ -221,7 +223,7 @@
 
                 DESParameters.setOddParity(kParam.getKey());
 
-                return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
             }
             
             throw new InvalidKeySpecException("Invalid KeySpec");
@@ -368,7 +370,7 @@
    {
        public PBEWithSHAAnd40BitRC2()
        {
-           super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbewithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+           super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
        }
    }
 
@@ -600,7 +602,7 @@
                 int ivSize = -1;
                 CipherParameters param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
                 
-                return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
             }
             
             throw new InvalidKeySpecException("Invalid KeySpec");
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java b/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
index b88ccae..16a14ec 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
@@ -8,6 +8,7 @@
 import java.security.spec.AlgorithmParameterSpec;
 
 import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
 import javax.crypto.NoSuchPaddingException;
 import javax.crypto.SecretKey;
 import javax.crypto.ShortBufferException;
@@ -37,9 +38,12 @@
 import org.bouncycastle.crypto.modes.OFBBlockCipher;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
 
 public class JCEStreamCipher
-    extends WrapCipherSpi implements PBE
+    extends CipherSpi
+    implements PBE
 {
     //
     // specs we can handle.
@@ -62,6 +66,8 @@
     private PBEParameterSpec        pbeSpec = null;
     private String                  pbeAlgorithm = null;
 
+    private AlgorithmParameters engineParams;
+
     protected JCEStreamCipher(
         StreamCipher engine,
         int          ivLength)
@@ -171,9 +177,9 @@
             throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
         }
         
-        if (key instanceof JCEPBEKey)
+        if (key instanceof BCPBEKey)
         {
-            JCEPBEKey   k = (JCEPBEKey)key;
+            BCPBEKey k = (BCPBEKey)key;
             
             if (k.getOID() != null)
             {
@@ -511,7 +517,7 @@
             super(new RC4Engine(), 0);
         }
     }
-    
+
     /**
      * PBEWithSHAAnd40BitRC4
      */
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java b/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
deleted file mode 100644
index b61acfa..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
+++ /dev/null
@@ -1,348 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import java.security.AlgorithmParameterGeneratorSpi;
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidParameterException;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.DSAParameterSpec;
-
-import javax.crypto.spec.DHGenParameterSpec;
-import javax.crypto.spec.DHParameterSpec;
-import javax.crypto.spec.IvParameterSpec;
-// BEGIN android-removed
-// import javax.crypto.spec.RC2ParameterSpec;
-// END android-removed
-
-import org.bouncycastle.crypto.generators.DHParametersGenerator;
-import org.bouncycastle.crypto.generators.DSAParametersGenerator;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
-// import org.bouncycastle.crypto.generators.GOST3410ParametersGenerator;
-// END android-removed
-import org.bouncycastle.crypto.params.DHParameters;
-import org.bouncycastle.crypto.params.DSAParameters;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.params.ElGamalParameters;
-// import org.bouncycastle.crypto.params.GOST3410Parameters;
-// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-// END android-removed
-
-public abstract class JDKAlgorithmParameterGenerator
-    extends AlgorithmParameterGeneratorSpi
-{
-    protected SecureRandom  random;
-    protected int           strength = 1024;
-
-    protected void engineInit(
-        int             strength,
-        SecureRandom    random)
-    {
-        this.strength = strength;
-        this.random = random;
-    }
-
-    public static class DH
-        extends JDKAlgorithmParameterGenerator
-    {
-        private int l = 0;
-
-        protected void engineInit(
-            AlgorithmParameterSpec  genParamSpec,
-            SecureRandom            random)
-            throws InvalidAlgorithmParameterException
-        {
-            if (!(genParamSpec instanceof DHGenParameterSpec))
-            {
-                throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
-            }
-            DHGenParameterSpec  spec = (DHGenParameterSpec)genParamSpec;
-
-            this.strength = spec.getPrimeSize();
-            this.l = spec.getExponentSize();
-            this.random = random;
-        }
-
-        protected AlgorithmParameters engineGenerateParameters()
-        {
-            DHParametersGenerator        pGen = new DHParametersGenerator();
-
-            if (random != null)
-            {
-                pGen.init(strength, 20, random);
-            }
-            else
-            {
-                pGen.init(strength, 20, new SecureRandom());
-            }
-
-            DHParameters                p = pGen.generateParameters();
-
-            AlgorithmParameters params;
-
-            try
-            {
-                params = AlgorithmParameters.getInstance("DH", BouncyCastleProvider.PROVIDER_NAME);
-                params.init(new DHParameterSpec(p.getP(), p.getG(), l));
-            }
-            catch (Exception e)
-            {
-                throw new RuntimeException(e.getMessage());
-            }
-
-            return params;
-        }
-    }
-
-    public static class DSA
-        extends JDKAlgorithmParameterGenerator
-    {
-        protected void engineInit(
-            int             strength,
-            SecureRandom    random)
-        {
-            if (strength < 512 || strength > 1024 || strength % 64 != 0)
-            {
-                throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
-            }
-
-            this.strength = strength;
-            this.random = random;
-        }
-
-        protected void engineInit(
-            AlgorithmParameterSpec  genParamSpec,
-            SecureRandom            random)
-            throws InvalidAlgorithmParameterException
-        {
-            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DSA parameter generation.");
-        }
-
-        protected AlgorithmParameters engineGenerateParameters()
-        {
-            DSAParametersGenerator pGen = new DSAParametersGenerator();
-
-            if (random != null)
-            {
-                pGen.init(strength, 20, random);
-            }
-            else
-            {
-                pGen.init(strength, 20, new SecureRandom());
-            }
-
-            DSAParameters p = pGen.generateParameters();
-
-            AlgorithmParameters params;
-
-            try
-            {
-                params = AlgorithmParameters.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
-                params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
-            }
-            catch (Exception e)
-            {
-                throw new RuntimeException(e.getMessage());
-            }
-
-            return params;
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class GOST3410
-    //     extends JDKAlgorithmParameterGenerator
-    // {
-    //     protected void engineInit(
-    //             AlgorithmParameterSpec  genParamSpec,
-    //             SecureRandom            random)
-    //     throws InvalidAlgorithmParameterException
-    //     {
-    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
-    //     }
-    //    
-    //     protected AlgorithmParameters engineGenerateParameters()
-    //     {
-    //         GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
-    //        
-    //         if (random != null)
-    //         {
-    //             pGen.init(strength, 2, random);
-    //         }
-    //         else
-    //         {
-    //             pGen.init(strength, 2, new SecureRandom());
-    //         }
-    //        
-    //         GOST3410Parameters p = pGen.generateParameters();
-    //        
-    //         AlgorithmParameters params;
-    //
-    //         try
-    //         {
-    //             params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
-    //             params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
-    //         }
-    //         catch (Exception e)
-    //         {
-    //             throw new RuntimeException(e.getMessage());
-    //         }
-    //
-    //         return params;
-    //     }
-    // }
-    //
-    // public static class ElGamal
-    //     extends JDKAlgorithmParameterGenerator
-    // {
-    //     private int l = 0;
-    //
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec  genParamSpec,
-    //         SecureRandom            random)
-    //         throws InvalidAlgorithmParameterException
-    //     {
-    //         if (!(genParamSpec instanceof DHGenParameterSpec))
-    //         {
-    //             throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
-    //         }
-    //         DHGenParameterSpec  spec = (DHGenParameterSpec)genParamSpec;
-    //
-    //         this.strength = spec.getPrimeSize();
-    //         this.l = spec.getExponentSize();
-    //         this.random = random;
-    //     }
-    //
-    //     protected AlgorithmParameters engineGenerateParameters()
-    //     {
-    //         ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
-    //
-    //         if (random != null)
-    //         {
-    //             pGen.init(strength, 20, random);
-    //         }
-    //         else
-    //         {
-    //             pGen.init(strength, 20, new SecureRandom());
-    //         }
-    //
-    //         ElGamalParameters p = pGen.generateParameters();
-    //
-    //         AlgorithmParameters params;
-    //
-    //         try
-    //         {
-    //             params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
-    //             params.init(new DHParameterSpec(p.getP(), p.getG(), l));
-    //         }
-    //         catch (Exception e)
-    //         {
-    //             throw new RuntimeException(e.getMessage());
-    //         }
-    //
-    //         return params;
-    //     }
-    // }
-    //
-    // public static class DES
-    //     extends JDKAlgorithmParameterGenerator
-    // {
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec  genParamSpec,
-    //         SecureRandom            random)
-    //         throws InvalidAlgorithmParameterException
-    //     {
-    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
-    //     }
-    //
-    //     protected AlgorithmParameters engineGenerateParameters()
-    //     {
-    //         byte[]  iv = new byte[8];
-    //
-    //         if (random == null)
-    //         {
-    //             random = new SecureRandom();
-    //         }
-    //
-    //         random.nextBytes(iv);
-    //
-    //         AlgorithmParameters params;
-    //
-    //         try
-    //         {
-    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
-    //             params.init(new IvParameterSpec(iv));
-    //         }
-    //         catch (Exception e)
-    //         {
-    //             throw new RuntimeException(e.getMessage());
-    //         }
-    //
-    //         return params;
-    //     }
-    // }
-    //
-    // public static class RC2
-    //     extends JDKAlgorithmParameterGenerator
-    // {
-    //     RC2ParameterSpec    spec = null;
-    //
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec  genParamSpec,
-    //         SecureRandom            random)
-    //         throws InvalidAlgorithmParameterException
-    //     {
-    //         if (genParamSpec instanceof RC2ParameterSpec)
-    //         {
-    //             spec = (RC2ParameterSpec)genParamSpec;
-    //             return;
-    //         }
-    //
-    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
-    //     }
-    //
-    //     protected AlgorithmParameters engineGenerateParameters()
-    //     {
-    //         AlgorithmParameters params;
-    //
-    //         if (spec == null)
-    //         {
-    //             byte[]  iv = new byte[8];
-    //
-    //             if (random == null)
-    //             {
-    //                 random = new SecureRandom();
-    //             }
-    //
-    //             random.nextBytes(iv);
-    //
-    //             try
-    //             {
-    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
-    //                 params.init(new IvParameterSpec(iv));
-    //             }
-    //             catch (Exception e)
-    //             {
-    //                 throw new RuntimeException(e.getMessage());
-    //             }
-    //         }
-    //         else
-    //         {
-    //             try
-    //             {
-    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
-    //                 params.init(spec);
-    //             }
-    //             catch (Exception e)
-    //             {
-    //                 throw new RuntimeException(e.getMessage());
-    //             }
-    //         }
-    //
-    //         return params;
-    //     }
-    // }
-    // END android-removed
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java b/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
index af88443..9a8cf9b 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
@@ -1,53 +1,25 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1OctetString;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.DERSequence;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-// import org.bouncycastle.asn1.oiw.ElGamalParameter;
-// END android-removed
-import org.bouncycastle.asn1.pkcs.DHParameter;
-import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
-// END android-removed
-import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
-import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
-import org.bouncycastle.asn1.pkcs.PBKDF2Params;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.DSAParameter;
-// BEGIN android-removed
-// import org.bouncycastle.jce.spec.ElGamalParameterSpec;
-// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-// import org.bouncycastle.jce.spec.IESParameterSpec;
-// END android-removed
-import org.bouncycastle.util.Arrays;
-
-import javax.crypto.spec.DHParameterSpec;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.OAEPParameterSpec;
-import javax.crypto.spec.PBEParameterSpec;
-import javax.crypto.spec.PSource;
-// BEGIN android-removed
-// import javax.crypto.spec.RC2ParameterSpec;
-// END android-removed
 import java.io.IOException;
 import java.security.AlgorithmParametersSpi;
 import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.DSAParameterSpec;
 import java.security.spec.InvalidParameterSpecException;
-import java.security.spec.MGF1ParameterSpec;
-import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.IESParameterSpec;
+// END android-removed
 
 public abstract class JDKAlgorithmParameters
     extends AlgorithmParametersSpi
@@ -72,286 +44,6 @@
     protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
         throws InvalidParameterSpecException;
 
-    public static class IVAlgorithmParameters
-        extends JDKAlgorithmParameters
-    {
-        private byte[]  iv;
-    
-        protected byte[] engineGetEncoded() 
-            throws IOException
-        {
-            return engineGetEncoded("ASN.1");
-        }
-    
-        protected byte[] engineGetEncoded(
-            String format) 
-            throws IOException
-        {
-            if (isASN1FormatString(format))
-            {
-                 return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
-            }
-    
-            if (format.equals("RAW"))
-            {
-                return Arrays.clone(iv);
-            }
-    
-            return null;
-        }
-    
-        protected AlgorithmParameterSpec localEngineGetParameterSpec(
-            Class paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (paramSpec == IvParameterSpec.class)
-            {
-                return new IvParameterSpec(iv);
-            }
-    
-            throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
-        }
-    
-        protected void engineInit(
-            AlgorithmParameterSpec paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (!(paramSpec instanceof IvParameterSpec))
-            {
-                throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
-            }
-    
-            this.iv = ((IvParameterSpec)paramSpec).getIV();
-        }
-    
-        protected void engineInit(
-            byte[] params) 
-            throws IOException
-        {
-            //
-            // check that we don't have a DER encoded octet string
-            //
-            if ((params.length % 8) != 0
-                    && params[0] == 0x04 && params[1] == params.length - 2)
-            {
-                ASN1OctetString oct = (ASN1OctetString)ASN1Object.fromByteArray(params);
-    
-                params = oct.getOctets();
-            }
-    
-            this.iv = Arrays.clone(params);
-        }
-    
-        protected void engineInit(
-            byte[] params,
-            String format) 
-            throws IOException
-        {
-            if (isASN1FormatString(format))
-            {
-                try
-                {
-                    ASN1OctetString oct = (ASN1OctetString)ASN1Object.fromByteArray(params);
-    
-                    engineInit(oct.getOctets());
-                }
-                catch (Exception e)
-                {
-                    throw new IOException("Exception decoding: " + e);
-                }
-    
-                return;
-            }
-    
-            if (format.equals("RAW"))
-            {
-                engineInit(params);
-                return;
-            }
-    
-            throw new IOException("Unknown parameters format in IV parameters object");
-        }
-    
-        protected String engineToString() 
-        {
-            return "IV Parameters";
-        }
-    }
-    
-    // BEGIN android-removed
-    // public static class RC2AlgorithmParameters
-    //     extends JDKAlgorithmParameters
-    // {
-    //     private static final short[] table = {
-    //        0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
-    //        0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
-    //        0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
-    //        0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
-    //        0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
-    //        0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
-    //        0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
-    //        0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
-    //        0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
-    //        0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
-    //        0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
-    //        0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
-    //        0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
-    //        0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
-    //        0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
-    //        0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
-    //     };
-    //
-    //     private static final short[] ekb = {
-    //        0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
-    //        0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
-    //        0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
-    //        0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
-    //        0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
-    //        0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
-    //        0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
-    //        0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
-    //        0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
-    //        0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
-    //        0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
-    //        0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
-    //        0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
-    //        0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
-    //        0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
-    //        0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
-    //     };
-    //
-    //     private byte[]  iv;
-    //     private int     parameterVersion = 58;
-    //
-    //     protected byte[] engineGetEncoded() 
-    //     {
-    //         return Arrays.clone(iv);
-    //     }
-    //
-    //     protected byte[] engineGetEncoded(
-    //         String format) 
-    //         throws IOException
-    //     {
-    //         if (isASN1FormatString(format))
-    //         {
-    //             if (parameterVersion == -1)
-    //             {
-    //                 return new RC2CBCParameter(engineGetEncoded()).getEncoded();
-    //             }
-    //             else
-    //             {
-    //                 return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
-    //             }
-    //         }
-    //
-    //         if (format.equals("RAW"))
-    //         {
-    //             return engineGetEncoded();
-    //         }
-    //
-    //         return null;
-    //     }
-    //
-    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-    //         Class paramSpec) 
-    //         throws InvalidParameterSpecException
-    //     {
-    //         if (paramSpec == RC2ParameterSpec.class)
-    //         {
-    //             if (parameterVersion != -1)
-    //             {
-    //                 if (parameterVersion < 256)
-    //                 {
-    //                     return new RC2ParameterSpec(ekb[parameterVersion], iv);
-    //                 }
-    //                 else
-    //                 {
-    //                     return new RC2ParameterSpec(parameterVersion, iv);
-    //                 }
-    //             }
-    //         }
-    //
-    //         if (paramSpec == IvParameterSpec.class)
-    //         {
-    //             return new IvParameterSpec(iv);
-    //         }
-    //
-    //         throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
-    //     }
-    //
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec paramSpec) 
-    //         throws InvalidParameterSpecException
-    //     {
-    //         if (paramSpec instanceof IvParameterSpec)
-    //         {
-    //             this.iv = ((IvParameterSpec)paramSpec).getIV();
-    //         }
-    //         else if (paramSpec instanceof RC2ParameterSpec)
-    //         {
-    //             int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
-    //             if (effKeyBits != -1)
-    //             {
-    //                 if (effKeyBits < 256)
-    //                 {
-    //                     parameterVersion = table[effKeyBits];
-    //                 }
-    //                 else
-    //                 {
-    //                     parameterVersion = effKeyBits;
-    //                 }
-    //             }
-    //
-    //             this.iv = ((RC2ParameterSpec)paramSpec).getIV();
-    //         }
-    //         else
-    //         {
-    //             throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
-    //         }
-    //     }
-    //
-    //     protected void engineInit(
-    //         byte[] params) 
-    //         throws IOException
-    //     {
-    //         this.iv = Arrays.clone(params);
-    //     }
-    //
-    //     protected void engineInit(
-    //         byte[] params,
-    //         String format) 
-    //         throws IOException
-    //     {
-    //         if (isASN1FormatString(format))
-    //         {
-    //             RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Object.fromByteArray(params));
-    //
-    //             if (p.getRC2ParameterVersion() != null)
-    //             {
-    //                 parameterVersion = p.getRC2ParameterVersion().intValue();
-    //             }
-    //
-    //             iv = p.getIV();
-    //
-    //             return;
-    //         }
-    //
-    //         if (format.equals("RAW"))
-    //         {
-    //             engineInit(params);
-    //             return;
-    //         }
-    //
-    //         throw new IOException("Unknown parameters format in IV parameters object");
-    //     }
-    //
-    //     protected String engineToString() 
-    //     {
-    //         return "RC2 Parameters";
-    //     }
-    // }
-    // END android-removed
-    
     public static class PBKDF2
         extends JDKAlgorithmParameters
     {
@@ -361,7 +53,7 @@
         {
             try
             {
-                return params.getEncoded(ASN1Encodable.DER);
+                return params.getEncoded(ASN1Encoding.DER);
             }
             catch (IOException e)
             {
@@ -412,7 +104,7 @@
             byte[] params)
             throws IOException
         {
-            this.params = PBKDF2Params.getInstance(ASN1Object.fromByteArray(params));
+            this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
         }
 
         protected void engineInit(
@@ -439,19 +131,19 @@
         extends JDKAlgorithmParameters
     {
         PKCS12PBEParams params;
-    
+
         protected byte[] engineGetEncoded() 
         {
             try
             {
-                return params.getEncoded(ASN1Encodable.DER);
+                return params.getEncoded(ASN1Encoding.DER);
             }
             catch (IOException e)
             {
                 throw new RuntimeException("Oooops! " + e.toString());
             }
         }
-    
+
         protected byte[] engineGetEncoded(
             String format) 
         {
@@ -459,10 +151,10 @@
             {
                 return engineGetEncoded();
             }
-    
+
             return null;
         }
-    
+
         protected AlgorithmParameterSpec localEngineGetParameterSpec(
             Class paramSpec) 
             throws InvalidParameterSpecException
@@ -472,10 +164,10 @@
                 return new PBEParameterSpec(params.getIV(),
                                 params.getIterations().intValue());
             }
-    
+
             throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
         }
-    
+
         protected void engineInit(
             AlgorithmParameterSpec paramSpec) 
             throws InvalidParameterSpecException
@@ -484,20 +176,20 @@
             {
                 throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
             }
-    
+
             PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
-    
+
             this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
                                 pbeSpec.getIterationCount());
         }
-    
+
         protected void engineInit(
             byte[] params) 
             throws IOException
         {
-            this.params = PKCS12PBEParams.getInstance(ASN1Object.fromByteArray(params));
+            this.params = PKCS12PBEParams.getInstance(ASN1Primitive.fromByteArray(params));
         }
-    
+
         protected void engineInit(
             byte[] params,
             String format) 
@@ -508,457 +200,17 @@
                 engineInit(params);
                 return;
             }
-    
+
             throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
         }
-    
+
         protected String engineToString() 
         {
             return "PKCS12 PBE Parameters";
         }
     }
 
-    public static class DH
-        extends JDKAlgorithmParameters
-    {
-        DHParameterSpec     currentSpec;
-
-        /**
-         * Return the PKCS#3 ASN.1 structure DHParameter.
-         * <p>
-         * <pre>
-         *  DHParameter ::= SEQUENCE {
-         *                   prime INTEGER, -- p
-         *                   base INTEGER, -- g
-         *                   privateValueLength INTEGER OPTIONAL}
-         * </pre>
-         */
-        protected byte[] engineGetEncoded() 
-        {
-            DHParameter dhP = new DHParameter(currentSpec.getP(), currentSpec.getG(), currentSpec.getL());
-
-            try
-            {
-                return dhP.getEncoded(ASN1Encodable.DER);                
-            }
-            catch (IOException e)
-            {
-                throw new RuntimeException("Error encoding DHParameters");
-            }
-        }
-
-        protected byte[] engineGetEncoded(
-            String format) 
-        {
-            if (isASN1FormatString(format))
-            {
-                return engineGetEncoded();
-            }
-
-            return null;
-        }
-
-        protected AlgorithmParameterSpec localEngineGetParameterSpec(
-            Class paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (paramSpec == DHParameterSpec.class)
-            {
-                return currentSpec;
-            }
-
-            throw new InvalidParameterSpecException("unknown parameter spec passed to DH parameters object.");
-        }
-
-        protected void engineInit(
-            AlgorithmParameterSpec paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (!(paramSpec instanceof DHParameterSpec))
-            {
-                throw new InvalidParameterSpecException("DHParameterSpec required to initialise a Diffie-Hellman algorithm parameters object");
-            }
-
-            this.currentSpec = (DHParameterSpec)paramSpec;
-        }
-
-        protected void engineInit(
-            byte[] params) 
-            throws IOException
-        {
-            try
-            {
-                DHParameter dhP = new DHParameter((ASN1Sequence)ASN1Object.fromByteArray(params));
-
-                if (dhP.getL() != null)
-                {
-                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG(), dhP.getL().intValue());
-                }
-                else
-                {
-                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG());
-                }
-            }
-            catch (ClassCastException e)
-            {
-                throw new IOException("Not a valid DH Parameter encoding.");
-            }
-            catch (ArrayIndexOutOfBoundsException e)
-            {
-                throw new IOException("Not a valid DH Parameter encoding.");
-            }
-        }
-
-        protected void engineInit(
-            byte[] params,
-            String format) 
-            throws IOException
-        {
-            if (isASN1FormatString(format))
-            {
-                engineInit(params);
-            }
-            else
-            {
-                throw new IOException("Unknown parameter format " + format);
-            }
-        }
-
-        protected String engineToString() 
-        {
-            return "Diffie-Hellman Parameters";
-        }
-    }
-
-    public static class DSA
-        extends JDKAlgorithmParameters
-    {
-        DSAParameterSpec     currentSpec;
-
-        /**
-         * Return the X.509 ASN.1 structure DSAParameter.
-         * <p>
-         * <pre>
-         *  DSAParameter ::= SEQUENCE {
-         *                   prime INTEGER, -- p
-         *                   subprime INTEGER, -- q
-         *                   base INTEGER, -- g}
-         * </pre>
-         */
-        protected byte[] engineGetEncoded() 
-        {
-            DSAParameter dsaP = new DSAParameter(currentSpec.getP(), currentSpec.getQ(), currentSpec.getG());
-
-            try
-            {
-                return dsaP.getEncoded(ASN1Encodable.DER);
-            }
-            catch (IOException e)
-            {
-                throw new RuntimeException("Error encoding DSAParameters");
-            }
-        }
-
-        protected byte[] engineGetEncoded(
-            String format) 
-        {
-            if (isASN1FormatString(format))
-            {
-                return engineGetEncoded();
-            }
-
-            return null;
-        }
-
-        protected AlgorithmParameterSpec localEngineGetParameterSpec(
-            Class paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (paramSpec == DSAParameterSpec.class)
-            {
-                return currentSpec;
-            }
-
-            throw new InvalidParameterSpecException("unknown parameter spec passed to DSA parameters object.");
-        }
-
-        protected void engineInit(
-            AlgorithmParameterSpec paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (!(paramSpec instanceof DSAParameterSpec))
-            {
-                throw new InvalidParameterSpecException("DSAParameterSpec required to initialise a DSA algorithm parameters object");
-            }
-
-            this.currentSpec = (DSAParameterSpec)paramSpec;
-        }
-
-        protected void engineInit(
-            byte[] params) 
-            throws IOException
-        {
-            try
-            {
-                DSAParameter dsaP = new DSAParameter((ASN1Sequence)ASN1Object.fromByteArray(params));
-
-                currentSpec = new DSAParameterSpec(dsaP.getP(), dsaP.getQ(), dsaP.getG());
-            }
-            catch (ClassCastException e)
-            {
-                throw new IOException("Not a valid DSA Parameter encoding.");
-            }
-            catch (ArrayIndexOutOfBoundsException e)
-            {
-                throw new IOException("Not a valid DSA Parameter encoding.");
-            }
-        }
-
-        protected void engineInit(
-            byte[] params,
-            String format) 
-            throws IOException
-        {
-            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-            {
-                engineInit(params);
-            }
-            else
-            {
-                throw new IOException("Unknown parameter format " + format);
-            }
-        }
-
-        protected String engineToString() 
-        {
-            return "DSA Parameters";
-        }
-    }
-    
     // BEGIN android-removed
-    // public static class GOST3410
-    //     extends JDKAlgorithmParameters
-    // {
-    //     GOST3410ParameterSpec     currentSpec;
-    //
-    //     /**
-    //      * Return the X.509 ASN.1 structure GOST3410Parameter.
-    //      * <p>
-    //      * <pre>
-    //      *  GOST3410Parameter ::= SEQUENCE {
-    //      *                   prime INTEGER, -- p
-    //      *                   subprime INTEGER, -- q
-    //      *                   base INTEGER, -- a}
-    //      * </pre>
-    //      */
-    //     protected byte[] engineGetEncoded()
-    //     {
-    //         GOST3410PublicKeyAlgParameters gost3410P = new GOST3410PublicKeyAlgParameters(new DERObjectIdentifier(currentSpec.getPublicKeyParamSetOID()), new DERObjectIdentifier(currentSpec.getDigestParamSetOID()), new DERObjectIdentifier(currentSpec.getEncryptionParamSetOID()));
-    //
-    //         try
-    //         {
-    //             return gost3410P.getEncoded(ASN1Encodable.DER);
-    //         }
-    //         catch (IOException e)
-    //         {
-    //             throw new RuntimeException("Error encoding GOST3410Parameters");
-    //         }
-    //     }
-    //
-    //     protected byte[] engineGetEncoded(
-    //             String format)
-    //     {
-    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-    //         {
-    //             return engineGetEncoded();
-    //         }
-    //
-    //         return null;
-    //     }
-    //
-    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-    //             Class paramSpec)
-    //     throws InvalidParameterSpecException
-    //     {
-    //         if (paramSpec == GOST3410PublicKeyParameterSetSpec.class)
-    //         {
-    //             return currentSpec;
-    //         }
-    //
-    //         throw new InvalidParameterSpecException("unknown parameter spec passed to GOST3410 parameters object.");
-    //     }
-    //
-    //     protected void engineInit(
-    //             AlgorithmParameterSpec paramSpec)
-    //     throws InvalidParameterSpecException
-    //     {
-    //         if (!(paramSpec instanceof GOST3410ParameterSpec))
-    //         {
-    //             throw new InvalidParameterSpecException("GOST3410ParameterSpec required to initialise a GOST3410 algorithm parameters object");
-    //         }
-    //
-    //         this.currentSpec = (GOST3410ParameterSpec)paramSpec;
-    //     }
-    //
-    //     protected void engineInit(
-    //             byte[] params)
-    //     throws IOException
-    //     {
-    //         try
-    //         {
-    //             ASN1Sequence seq = (ASN1Sequence) ASN1Object.fromByteArray(params);
-    //
-    //             this.currentSpec = GOST3410ParameterSpec.fromPublicKeyAlg(
-    //                 new GOST3410PublicKeyAlgParameters(seq));
-    //         }
-    //         catch (ClassCastException e)
-    //         {
-    //             throw new IOException("Not a valid GOST3410 Parameter encoding.");
-    //         }
-    //         catch (ArrayIndexOutOfBoundsException e)
-    //         {
-    //             throw new IOException("Not a valid GOST3410 Parameter encoding.");
-    //         }
-    //     }
-    //
-    //     protected void engineInit(
-    //             byte[] params,
-    //             String format)
-    //     throws IOException
-    //     {
-    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-    //         {
-    //             engineInit(params);
-    //         }
-    //         else
-    //         {
-    //             throw new IOException("Unknown parameter format " + format);
-    //         }
-    //     }
-    //
-    //     protected String engineToString()
-    //     {
-    //         return "GOST3410 Parameters";
-    //     }
-    // }
-
-    // public static class ElGamal
-    //     extends JDKAlgorithmParameters
-    // {
-    //     ElGamalParameterSpec     currentSpec;
-    //
-    //     /**
-    //      * Return the X.509 ASN.1 structure ElGamalParameter.
-    //      * <p>
-    //      * <pre>
-    //      *  ElGamalParameter ::= SEQUENCE {
-    //      *                   prime INTEGER, -- p
-    //      *                   base INTEGER, -- g}
-    //      * </pre>
-    //      */
-    //     protected byte[] engineGetEncoded() 
-    //     {
-    //         ElGamalParameter elP = new ElGamalParameter(currentSpec.getP(), currentSpec.getG());
-    //
-    //         try
-    //         {
-    //             return elP.getEncoded(ASN1Encodable.DER);
-    //         }
-    //         catch (IOException e)
-    //         {
-    //             throw new RuntimeException("Error encoding ElGamalParameters");
-    //         }
-    //     }
-    //
-    //     protected byte[] engineGetEncoded(
-    //         String format) 
-    //     {
-    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-    //         {
-    //             return engineGetEncoded();
-    //         }
-    //
-    //         return null;
-    //     }
-    //
-    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-    //         Class paramSpec) 
-    //         throws InvalidParameterSpecException
-    //     {
-    //         if (paramSpec == ElGamalParameterSpec.class)
-    //         {
-    //             return currentSpec;
-    //         }
-    //         else if (paramSpec == DHParameterSpec.class)
-    //         {
-    //             return new DHParameterSpec(currentSpec.getP(), currentSpec.getG());
-    //         }
-    //
-    //         throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
-    //     }
-    //
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec paramSpec) 
-    //         throws InvalidParameterSpecException
-    //     {
-    //         if (!(paramSpec instanceof ElGamalParameterSpec) && !(paramSpec instanceof DHParameterSpec))
-    //         {
-    //             throw new InvalidParameterSpecException("DHParameterSpec required to initialise a ElGamal algorithm parameters object");
-    //         }
-    //
-    //         if (paramSpec instanceof ElGamalParameterSpec)
-    //         {
-    //             this.currentSpec = (ElGamalParameterSpec)paramSpec;
-    //         }
-    //         else
-    //         {
-    //             DHParameterSpec s = (DHParameterSpec)paramSpec;
-    //
-    //             this.currentSpec = new ElGamalParameterSpec(s.getP(), s.getG());
-    //         }
-    //     }
-    //
-    //     protected void engineInit(
-    //         byte[] params) 
-    //         throws IOException
-    //     {
-    //         try
-    //         {
-    //             ElGamalParameter elP = new ElGamalParameter((ASN1Sequence)ASN1Object.fromByteArray(params));
-    //
-    //             currentSpec = new ElGamalParameterSpec(elP.getP(), elP.getG());
-    //         }
-    //         catch (ClassCastException e)
-    //         {
-    //             throw new IOException("Not a valid ElGamal Parameter encoding.");
-    //         }
-    //         catch (ArrayIndexOutOfBoundsException e)
-    //         {
-    //             throw new IOException("Not a valid ElGamal Parameter encoding.");
-    //         }
-    //     }
-    //
-    //     protected void engineInit(
-    //         byte[] params,
-    //         String format) 
-    //         throws IOException
-    //     {
-    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-    //         {
-    //             engineInit(params);
-    //         }
-    //         else
-    //         {
-    //             throw new IOException("Unknown parameter format " + format);
-    //         }
-    //     }
-    //
-    //     protected String engineToString() 
-    //     {
-    //         return "ElGamal Parameters";
-    //     }
-    // }
-    //
     // public static class IES
     //     extends JDKAlgorithmParameters
     // {
@@ -978,7 +230,7 @@
     //             v.add(new DEROctetString(currentSpec.getEncodingV()));
     //             v.add(new DERInteger(currentSpec.getMacKeySize()));
     //
-    //             return new DERSequence(v).getEncoded(ASN1Encodable.DER);
+    //             return new DERSequence(v).getEncoded(ASN1Encoding.DER);
     //         }
     //         catch (IOException e)
     //         {
@@ -1027,7 +279,7 @@
     //     {
     //         try
     //         {
-    //             ASN1Sequence s = (ASN1Sequence)ASN1Object.fromByteArray(params);
+    //             ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
     //
     //             this.currentSpec = new IESParameterSpec(
     //                                     ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
@@ -1065,234 +317,4 @@
     //     }
     // }
     // END android-removed
-    
-    public static class OAEP
-        extends JDKAlgorithmParameters
-    {
-        OAEPParameterSpec     currentSpec;
-    
-        /**
-         * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
-         */
-        protected byte[] engineGetEncoded() 
-        {
-            AlgorithmIdentifier     hashAlgorithm = new AlgorithmIdentifier(
-                                                            JCEDigestUtil.getOID(currentSpec.getDigestAlgorithm()),
-                                                            // BEGIN android-changed
-                                                            DERNull.INSTANCE);
-                                                            // END android-changed
-            MGF1ParameterSpec       mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
-            AlgorithmIdentifier     maskGenAlgorithm = new AlgorithmIdentifier(
-                                                            PKCSObjectIdentifiers.id_mgf1, 
-                                                            // BEGIN android-changed
-                                                            new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
-                                                            // END android-changed
-            PSource.PSpecified      pSource = (PSource.PSpecified)currentSpec.getPSource();
-            AlgorithmIdentifier     pSourceAlgorithm = new AlgorithmIdentifier(
-                                                            PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
-            RSAESOAEPparams         oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
-    
-            try
-            {
-                return oaepP.getEncoded(ASN1Encodable.DER);
-            }
-            catch (IOException e)
-            {
-                throw new RuntimeException("Error encoding OAEPParameters");
-            }
-        }
-    
-        protected byte[] engineGetEncoded(
-            String format) 
-        {
-            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-            {
-                return engineGetEncoded();
-            }
-    
-            return null;
-        }
-    
-        protected AlgorithmParameterSpec localEngineGetParameterSpec(
-            Class paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (paramSpec == OAEPParameterSpec.class && currentSpec != null)
-            {
-                return currentSpec;
-            }
-    
-            throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
-        }
-    
-        protected void engineInit(
-            AlgorithmParameterSpec paramSpec) 
-            throws InvalidParameterSpecException
-        {
-            if (!(paramSpec instanceof OAEPParameterSpec))
-            {
-                throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
-            }
-    
-            this.currentSpec = (OAEPParameterSpec)paramSpec;
-        }
-    
-        protected void engineInit(
-            byte[] params) 
-            throws IOException
-        {
-            try
-            {
-                RSAESOAEPparams oaepP = new RSAESOAEPparams((ASN1Sequence)ASN1Object.fromByteArray(params));
-
-                currentSpec = new OAEPParameterSpec(
-                                       oaepP.getHashAlgorithm().getObjectId().getId(), 
-                                       oaepP.getMaskGenAlgorithm().getObjectId().getId(), 
-                                       new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getObjectId().getId()),
-                                       new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
-            }
-            catch (ClassCastException e)
-            {
-                throw new IOException("Not a valid OAEP Parameter encoding.");
-            }
-            catch (ArrayIndexOutOfBoundsException e)
-            {
-                throw new IOException("Not a valid OAEP Parameter encoding.");
-            }
-        }
-    
-        protected void engineInit(
-            byte[] params,
-            String format) 
-            throws IOException
-        {
-            if (format.equalsIgnoreCase("X.509")
-                    || format.equalsIgnoreCase("ASN.1"))
-            {
-                engineInit(params);
-            }
-            else
-            {
-                throw new IOException("Unknown parameter format " + format);
-            }
-        }
-    
-        protected String engineToString() 
-        {
-            return "OAEP Parameters";
-        }
-    }
-    
-    // BEGIN android-removed
-    // public static class PSS
-    //     extends JDKAlgorithmParameters
-    // {  
-    //     PSSParameterSpec     currentSpec;
-    //
-    //     /**
-    //      * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
-    //      */
-    //     protected byte[] engineGetEncoded() 
-    //         throws IOException
-    //     {
-    //         PSSParameterSpec    pssSpec = currentSpec;
-    //         AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
-    //                                             JCEDigestUtil.getOID(pssSpec.getDigestAlgorithm()),
-    //                                             // BEGIN android-changed
-    //                                             DERNull.INSTANCE);
-    //                                             // END android-changed
-    //         MGF1ParameterSpec   mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
-    //         AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
-    //                                             PKCSObjectIdentifiers.id_mgf1, 
-    //                                             // BEGIN android-changed
-    //                                             new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
-    //                                             // END android-changed
-    //         RSASSAPSSparams     pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new DERInteger(pssSpec.getSaltLength()), new DERInteger(pssSpec.getTrailerField()));
-    //
-    //         return pssP.getEncoded("DER");
-    //     }
-    //
-    //     protected byte[] engineGetEncoded(
-    //         String format) 
-    //         throws IOException
-    //     {
-    //         if (format.equalsIgnoreCase("X.509")
-    //                 || format.equalsIgnoreCase("ASN.1"))
-    //         {
-    //             return engineGetEncoded();
-    //         }
-    //
-    //         return null;
-    //     }
-    //
-    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
-    //         Class paramSpec) 
-    //         throws InvalidParameterSpecException
-    //     {
-    //         if (paramSpec == PSSParameterSpec.class && currentSpec != null)
-    //         {
-    //             return currentSpec;
-    //         }
-    //
-    //         throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
-    //     }
-    //
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec paramSpec) 
-    //         throws InvalidParameterSpecException
-    //     {
-    //         if (!(paramSpec instanceof PSSParameterSpec))
-    //         {
-    //             throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
-    //         }
-    //
-    //         this.currentSpec = (PSSParameterSpec)paramSpec;
-    //     }
-    //
-    //     protected void engineInit(
-    //         byte[] params) 
-    //         throws IOException
-    //     {
-    //         try
-    //         {
-    //             RSASSAPSSparams pssP = new RSASSAPSSparams((ASN1Sequence)ASN1Object.fromByteArray(params));
-    //
-    //             currentSpec = new PSSParameterSpec(
-    //                                    pssP.getHashAlgorithm().getObjectId().getId(), 
-    //                                    pssP.getMaskGenAlgorithm().getObjectId().getId(), 
-    //                                    new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getObjectId().getId()),
-    //                                    pssP.getSaltLength().getValue().intValue(),
-    //                                    pssP.getTrailerField().getValue().intValue());
-    //         }
-    //         catch (ClassCastException e)
-    //         {
-    //             throw new IOException("Not a valid PSS Parameter encoding.");
-    //         }
-    //         catch (ArrayIndexOutOfBoundsException e)
-    //         {
-    //             throw new IOException("Not a valid PSS Parameter encoding.");
-    //         }
-    //     }
-    //
-    //     protected void engineInit(
-    //         byte[] params,
-    //         String format) 
-    //         throws IOException
-    //     {
-    //         if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
-    //         {
-    //             engineInit(params);
-    //         }
-    //         else
-    //         {
-    //             throw new IOException("Unknown parameter format " + format);
-    //         }
-    //     }
-    //
-    //     protected String engineToString() 
-    //     {
-    //         return "PSS Parameters";
-    //     }
-    // }
-    // END android-removed
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
index 5d016d0..379120e 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
@@ -1,16 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.DSAParameter;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
-import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -21,6 +10,21 @@
 import java.security.spec.DSAPrivateKeySpec;
 import java.util.Enumeration;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
 public class JDKDSAPrivateKey
     implements DSAPrivateKey, PKCS12BagAttributeCarrier
 {
@@ -51,9 +55,10 @@
 
     JDKDSAPrivateKey(
         PrivateKeyInfo  info)
+        throws IOException
     {
         DSAParameter    params = new DSAParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
-        DERInteger      derX = (DERInteger)info.getPrivateKey();
+        DERInteger      derX = ASN1Integer.getInstance(info.parsePrivateKey());
 
         this.x = derX.getValue();
         this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
@@ -89,9 +94,16 @@
      */
     public byte[] getEncoded()
     {
-        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).getDERObject()), new DERInteger(getX()));
+        try
+        {
+            PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(getX()));
 
-        return info.getDEREncoded();
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
     }
 
     public DSAParams getParams()
@@ -127,13 +139,13 @@
     }
     
     public void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
     {
         attrCarrier.setBagAttribute(oid, attribute);
     }
 
-    public DEREncodable getBagAttribute(
+    public ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid)
     {
         return attrCarrier.getBagAttribute(oid);
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
index 392f532..16a964d 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
@@ -1,15 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.DSAParameter;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
-
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -19,6 +9,17 @@
 import java.security.spec.DSAParameterSpec;
 import java.security.spec.DSAPublicKeySpec;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
 public class JDKDSAPublicKey
     implements DSAPublicKey
 {
@@ -64,7 +65,7 @@
 
         try
         {
-            derY = (DERInteger)info.getPublicKey();
+            derY = (DERInteger)info.parsePublicKey();
         }
         catch (IOException e)
         {
@@ -81,7 +82,7 @@
         }
     }
 
-    private boolean isNotNull(DEREncodable parameters)
+    private boolean isNotNull(ASN1Encodable parameters)
     {
         return parameters != null && !DERNull.INSTANCE.equals(parameters);
     }
@@ -98,12 +99,19 @@
 
     public byte[] getEncoded()
     {
-        if (dsaSpec == null)
+        try
         {
-            return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new DERInteger(y)).getDEREncoded();
-        }
+            if (dsaSpec == null)
+            {
+                return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new DERInteger(y)).getEncoded(ASN1Encoding.DER);
+            }
 
-        return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).getDERObject()), new DERInteger(y)).getDEREncoded();
+            return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(y)).getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
     }
 
     public DSAParams getParams()
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
deleted file mode 100644
index 3ed5821..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
+++ /dev/null
@@ -1,570 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import java.io.IOException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyFactorySpi;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.DSAPublicKey;
-import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.DSAPrivateKeySpec;
-import java.security.spec.DSAPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPrivateKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-import javax.crypto.interfaces.DHPrivateKey;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHPrivateKeySpec;
-import javax.crypto.spec.DHPublicKeySpec;
-
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-// BEGIN android-removed
-// import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
-// import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
-// import org.bouncycastle.jce.spec.ElGamalPrivateKeySpec;
-// import org.bouncycastle.jce.spec.ElGamalPublicKeySpec;
-// import org.bouncycastle.jce.spec.GOST3410PrivateKeySpec;
-// import org.bouncycastle.jce.spec.GOST3410PublicKeySpec;
-// END android-removed
-
-public abstract class JDKKeyFactory
-    extends KeyFactorySpi
-{
-    // BEGIN android-removed
-    // protected boolean elGamalFactory = false;
-    // END android-removed
-    
-    public JDKKeyFactory()
-    {
-    }
-
-    protected PrivateKey engineGeneratePrivate(
-        KeySpec keySpec)
-        throws InvalidKeySpecException
-    {
-        if (keySpec instanceof PKCS8EncodedKeySpec)
-        {
-            try
-            {
-                return JDKKeyFactory.createPrivateKeyFromDERStream(
-                    ((PKCS8EncodedKeySpec)keySpec).getEncoded());
-            }
-            catch (Exception e)
-            {
-                throw new InvalidKeySpecException(e.toString());
-            }
-        }
-
-        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
-    }
-
-    protected PublicKey engineGeneratePublic(
-        KeySpec    keySpec)
-        throws InvalidKeySpecException
-    {
-        if (keySpec instanceof X509EncodedKeySpec)
-        {
-            try
-            {
-                return JDKKeyFactory.createPublicKeyFromDERStream(
-                    ((X509EncodedKeySpec)keySpec).getEncoded());
-            }
-            catch (Exception e)
-            {
-                throw new InvalidKeySpecException(e.toString());
-            }
-        }
-
-        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
-    }
-    
-    protected KeySpec engineGetKeySpec(
-        Key    key,
-        Class    spec)
-    throws InvalidKeySpecException
-    {
-       if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
-       {
-               return new PKCS8EncodedKeySpec(key.getEncoded());
-       }
-       else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
-       {
-               return new X509EncodedKeySpec(key.getEncoded());
-       }
-       else if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
-       {
-            RSAPublicKey    k = (RSAPublicKey)key;
-
-            return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
-       }
-       else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof RSAPrivateKey)
-       {
-            RSAPrivateKey    k = (RSAPrivateKey)key;
-
-            return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
-       }
-       else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
-       {
-            RSAPrivateCrtKey    k = (RSAPrivateCrtKey)key;
-
-            return new RSAPrivateCrtKeySpec(
-                            k.getModulus(), k.getPublicExponent(),
-                            k.getPrivateExponent(),
-                            k.getPrimeP(), k.getPrimeQ(),
-                            k.getPrimeExponentP(), k.getPrimeExponentQ(),
-                            k.getCrtCoefficient());
-       }
-       else if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
-       {
-           DHPrivateKey k = (DHPrivateKey)key;
-           
-           return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
-       }
-       else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
-       {
-           DHPublicKey k = (DHPublicKey)key;
-           
-           return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
-       }
-       // BEGIN android-added
-       else if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
-       {
-            DSAPublicKey    k = (DSAPublicKey)key;
-
-            return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
-       }
-       else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof DSAPrivateKey)
-       {
-            DSAPrivateKey    k = (DSAPrivateKey)key;
-
-            return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
-       }
-       // END android-added
-
-       throw new RuntimeException("not implemented yet " + key + " " + spec);
-    }
-
-    protected Key engineTranslateKey(
-        Key    key)
-        throws InvalidKeyException
-    {
-        if (key instanceof RSAPublicKey)
-        {
-            return new JCERSAPublicKey((RSAPublicKey)key);
-        }
-        else if (key instanceof RSAPrivateCrtKey)
-        {
-            return new JCERSAPrivateCrtKey((RSAPrivateCrtKey)key);
-        }
-        else if (key instanceof RSAPrivateKey)
-        {
-            return new JCERSAPrivateKey((RSAPrivateKey)key);
-        }
-        else if (key instanceof DHPublicKey)
-        {
-            // BEGIN android-removed
-            // if (elGamalFactory)
-            // {
-            //     return new JCEElGamalPublicKey((DHPublicKey)key);
-            // }
-            // else
-            // {
-            // END android-removed
-                return new JCEDHPublicKey((DHPublicKey)key);
-            // BEGIN android-removed
-            // }
-            // END android-removed
-        }
-        else if (key instanceof DHPrivateKey)
-        {
-            // BEGIN android-removed
-            // if (elGamalFactory)
-            // {
-            //     return new JCEElGamalPrivateKey((DHPrivateKey)key);
-            // }
-            // else
-            // {
-            // END android-removed
-                return new JCEDHPrivateKey((DHPrivateKey)key);
-            // BEGIN android-removed
-            // }
-            // END android-removed
-        }
-        else if (key instanceof DSAPublicKey)
-        {
-            return new JDKDSAPublicKey((DSAPublicKey)key);
-        }
-        else if (key instanceof DSAPrivateKey)
-        {
-            return new JDKDSAPrivateKey((DSAPrivateKey)key);
-        }
-        // BEGIN android-removed
-        // else if (key instanceof ElGamalPublicKey)
-        // {
-        //     return new JCEElGamalPublicKey((ElGamalPublicKey)key);
-        // }
-        // else if (key instanceof ElGamalPrivateKey)
-        // {
-        //    return new JCEElGamalPrivateKey((ElGamalPrivateKey)key);
-        // }
-        // END android-removed
-
-        throw new InvalidKeyException("key type unknown");
-    }
-
-    /**
-     * create a public key from the given DER encoded input stream. 
-     */ 
-    public static PublicKey createPublicKeyFromDERStream(
-        byte[]         in)
-        throws IOException
-    {
-        return createPublicKeyFromPublicKeyInfo(
-            new SubjectPublicKeyInfo((ASN1Sequence) ASN1Object.fromByteArray(in)));
-    }
-
-    /**
-     * create a public key from the given public key info object.
-     */ 
-    static PublicKey createPublicKeyFromPublicKeyInfo(
-        SubjectPublicKeyInfo         info)
-    {
-        DERObjectIdentifier     algOid = info.getAlgorithmId().getObjectId();
-        
-        if (RSAUtil.isRsaOid(algOid))
-        {
-            return new JCERSAPublicKey(info);
-        }
-        else if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
-        {
-            return new JCEDHPublicKey(info);
-        }
-        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
-        {
-            return new JCEDHPublicKey(info);
-        }
-        // BEGIN android-removed
-        // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
-        // {
-        //     return new JCEElGamalPublicKey(info);
-        // }
-        // END android-removed
-        else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
-        {
-            return new JDKDSAPublicKey(info);
-        }
-        else if (algOid.equals(OIWObjectIdentifiers.dsaWithSHA1))
-        {
-            return new JDKDSAPublicKey(info);
-        }
-        else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-        {
-            return new JCEECPublicKey(info);
-        }
-        // BEGIN android-removed
-        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
-        // {
-        //     return new JDKGOST3410PublicKey(info);
-        // }
-        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
-        // {
-        //     return new JCEECPublicKey(info);
-        // }
-        else
-        {
-            throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-        }
-    }
-
-    /**
-     * create a private key from the given DER encoded input stream. 
-     */ 
-    protected static PrivateKey createPrivateKeyFromDERStream(
-        byte[]         in)
-        throws IOException
-    {
-        return createPrivateKeyFromPrivateKeyInfo(
-            new PrivateKeyInfo((ASN1Sequence) ASN1Object.fromByteArray(in)));
-    }
-
-    /**
-     * create a private key from the given public key info object.
-     */ 
-    static PrivateKey createPrivateKeyFromPrivateKeyInfo(
-        PrivateKeyInfo      info)
-    {
-        DERObjectIdentifier     algOid = info.getAlgorithmId().getObjectId();
-        
-        if (RSAUtil.isRsaOid(algOid))
-        {
-              return new JCERSAPrivateCrtKey(info);
-        }
-        else if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
-        {
-              return new JCEDHPrivateKey(info);
-        }
-        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
-        {
-              return new JCEDHPrivateKey(info);
-        }
-        // BEGIN android-removed
-        // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
-        // {
-        //       return new JCEElGamalPrivateKey(info);
-        // }
-        // END android-removed
-        else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
-        {
-              return new JDKDSAPrivateKey(info);
-        }
-        else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-        {
-              return new JCEECPrivateKey(info);
-        }
-        // BEGIN android-removed
-        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
-        // {
-        //       return new JDKGOST3410PrivateKey(info);
-        // }
-        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
-        // {
-        //       return new JCEECPrivateKey(info);
-        // }
-        // END android-removed
-        else
-        {
-            throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-        }
-    }
-
-    public static class RSA
-        extends JDKKeyFactory
-    {
-        public RSA()
-        {
-        }
-
-        protected PrivateKey engineGeneratePrivate(
-            KeySpec    keySpec)
-            throws InvalidKeySpecException
-        {
-            if (keySpec instanceof PKCS8EncodedKeySpec)
-            {
-                try
-                {
-                    return JDKKeyFactory.createPrivateKeyFromDERStream(
-                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
-                }
-                catch (Exception e)
-                {
-                    //
-                    // in case it's just a RSAPrivateKey object...
-                    //
-                    try
-                    {
-                        return new JCERSAPrivateCrtKey(
-                            new RSAPrivateKeyStructure(
-                                (ASN1Sequence) ASN1Object.fromByteArray(((PKCS8EncodedKeySpec)keySpec).getEncoded())));
-                    }
-                    catch (Exception ex)
-                    {
-                        throw new InvalidKeySpecException(ex.toString());
-                    }
-                }
-            }
-            else if (keySpec instanceof RSAPrivateCrtKeySpec)
-            {
-                return new JCERSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
-            }
-            else if (keySpec instanceof RSAPrivateKeySpec)
-            {
-                return new JCERSAPrivateKey((RSAPrivateKeySpec)keySpec);
-            }
-    
-            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
-        }
-    
-        protected PublicKey engineGeneratePublic(
-            KeySpec    keySpec)
-            throws InvalidKeySpecException
-        {
-            if (keySpec instanceof RSAPublicKeySpec)
-            {
-                return new JCERSAPublicKey((RSAPublicKeySpec)keySpec);
-            }
-
-            return super.engineGeneratePublic(keySpec);
-        }
-    }
-
-    public static class DH
-        extends JDKKeyFactory
-    {
-        public DH()
-        {
-        }
-
-        protected PrivateKey engineGeneratePrivate(
-            KeySpec    keySpec)
-            throws InvalidKeySpecException
-        {
-            if (keySpec instanceof DHPrivateKeySpec)
-            {
-                return new JCEDHPrivateKey((DHPrivateKeySpec)keySpec);
-            }
-
-            return super.engineGeneratePrivate(keySpec);
-        }
-    
-        protected PublicKey engineGeneratePublic(
-            KeySpec    keySpec)
-            throws InvalidKeySpecException
-        {
-            if (keySpec instanceof DHPublicKeySpec)
-            {
-                return new JCEDHPublicKey((DHPublicKeySpec)keySpec);
-            }
-
-            return super.engineGeneratePublic(keySpec);
-        }
-    }
-
-    public static class DSA
-        extends JDKKeyFactory
-    {
-        public DSA()
-        {
-        }
-
-        protected PrivateKey engineGeneratePrivate(
-            KeySpec    keySpec)
-            throws InvalidKeySpecException
-        {
-            if (keySpec instanceof DSAPrivateKeySpec)
-            {
-                return new JDKDSAPrivateKey((DSAPrivateKeySpec)keySpec);
-            }
-
-            return super.engineGeneratePrivate(keySpec);
-        }
-    
-        protected PublicKey engineGeneratePublic(
-            KeySpec    keySpec)
-            throws InvalidKeySpecException
-        {
-            if (keySpec instanceof DSAPublicKeySpec)
-            {
-                return new JDKDSAPublicKey((DSAPublicKeySpec)keySpec);
-            }
-
-            return super.engineGeneratePublic(keySpec);
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class GOST3410
-    //     extends JDKKeyFactory
-    // {
-    //     public GOST3410()
-    //     {
-    //     }
-    //
-    //     protected PrivateKey engineGeneratePrivate(
-    //             KeySpec    keySpec)
-    //     throws InvalidKeySpecException
-    //     {
-    //         if (keySpec instanceof GOST3410PrivateKeySpec)
-    //         {
-    //             return new JDKGOST3410PrivateKey((GOST3410PrivateKeySpec)keySpec);
-    //         }
-    //
-    //         return super.engineGeneratePrivate(keySpec);
-    //     }
-    //
-    //     protected PublicKey engineGeneratePublic(
-    //             KeySpec    keySpec)
-    //     throws InvalidKeySpecException
-    //     {
-    //         if (keySpec instanceof GOST3410PublicKeySpec)
-    //         {
-    //             return new JDKGOST3410PublicKey((GOST3410PublicKeySpec)keySpec);
-    //         }
-    //
-    //         return super.engineGeneratePublic(keySpec);
-    //     }
-    // }
-    
-    // public static class ElGamal
-    //     extends JDKKeyFactory
-    // {
-    //     public ElGamal()
-    //     {
-    //         elGamalFactory = true;
-    //     }
-    //
-    //     protected PrivateKey engineGeneratePrivate(
-    //         KeySpec    keySpec)
-    //         throws InvalidKeySpecException
-    //     {
-    //         if (keySpec instanceof ElGamalPrivateKeySpec)
-    //         {
-    //             return new JCEElGamalPrivateKey((ElGamalPrivateKeySpec)keySpec);
-    //         }
-    //         else if (keySpec instanceof DHPrivateKeySpec)
-    //         {
-    //             return new JCEElGamalPrivateKey((DHPrivateKeySpec)keySpec);
-    //         }
-    //
-    //         return super.engineGeneratePrivate(keySpec);
-    //     }
-    //
-    //     protected PublicKey engineGeneratePublic(
-    //         KeySpec    keySpec)
-    //         throws InvalidKeySpecException
-    //     {
-    //         if (keySpec instanceof ElGamalPublicKeySpec)
-    //         {
-    //             return new JCEElGamalPublicKey((ElGamalPublicKeySpec)keySpec);
-    //         }
-    //         else if (keySpec instanceof DHPublicKeySpec)
-    //         {
-    //             return new JCEElGamalPublicKey((DHPublicKeySpec)keySpec);
-    //         }
-    //
-    //         return super.engineGeneratePublic(keySpec);
-    //     }
-    // }
-    //
-    //
-    //
-    // /**
-    //  * This isn't really correct, however the class path project API seems to think such
-    //  * a key factory will exist.
-    //  */
-    // public static class X509
-    //     extends JDKKeyFactory
-    // {
-    //     public X509()
-    //     {
-    //     }
-    // }
-    // END android-removed
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java b/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
deleted file mode 100644
index e0f4246..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
+++ /dev/null
@@ -1,410 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
-import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator;
-import org.bouncycastle.crypto.generators.DHParametersGenerator;
-import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
-import org.bouncycastle.crypto.generators.DSAParametersGenerator;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator;
-// import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
-// import org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator;
-// END android-removed
-import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
-import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
-import org.bouncycastle.crypto.params.DHParameters;
-import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
-import org.bouncycastle.crypto.params.DHPublicKeyParameters;
-import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
-import org.bouncycastle.crypto.params.DSAParameters;
-import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
-import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.params.ElGamalKeyGenerationParameters;
-// import org.bouncycastle.crypto.params.ElGamalParameters;
-// import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
-// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
-// import org.bouncycastle.crypto.params.GOST3410KeyGenerationParameters;
-// import org.bouncycastle.crypto.params.GOST3410Parameters;
-// import org.bouncycastle.crypto.params.GOST3410PrivateKeyParameters;
-// import org.bouncycastle.crypto.params.GOST3410PublicKeyParameters;
-// END android-removed
-import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
-import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
-// BEGIN android-removed
-// import org.bouncycastle.jce.spec.ElGamalParameterSpec;
-// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
-// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
-// END android-removed
-
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.DSAParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.Hashtable;
-
-import javax.crypto.spec.DHParameterSpec;
-
-public abstract class JDKKeyPairGenerator
-    extends KeyPairGenerator
-{
-    public JDKKeyPairGenerator(
-        String              algorithmName)
-    {
-        super(algorithmName);
-    }
-
-    public abstract void initialize(int strength, SecureRandom random);
-
-    public abstract KeyPair generateKeyPair();
-
-    public static class RSA
-        extends JDKKeyPairGenerator
-    {
-        final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
-        final static int defaultTests = 12;
-
-        RSAKeyGenerationParameters  param;
-        RSAKeyPairGenerator         engine;
-
-        public RSA()
-        {
-            super("RSA");
-
-            engine = new RSAKeyPairGenerator();
-            param = new RSAKeyGenerationParameters(defaultPublicExponent,
-                            new SecureRandom(), 2048, defaultTests);
-            engine.init(param);
-        }
-
-        public void initialize(
-            int             strength,
-            SecureRandom    random)
-        {
-            param = new RSAKeyGenerationParameters(defaultPublicExponent,
-                            random, strength, defaultTests);
-
-            engine.init(param);
-        }
-
-        public void initialize(
-            AlgorithmParameterSpec  params,
-            SecureRandom            random)
-            throws InvalidAlgorithmParameterException
-        {
-            if (!(params instanceof RSAKeyGenParameterSpec))
-            {
-                throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
-            }
-            RSAKeyGenParameterSpec     rsaParams = (RSAKeyGenParameterSpec)params;
-
-            param = new RSAKeyGenerationParameters(
-                            rsaParams.getPublicExponent(),
-                            random, rsaParams.getKeysize(), defaultTests);
-
-            engine.init(param);
-        }
-
-        public KeyPair generateKeyPair()
-        {
-            AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
-            RSAKeyParameters            pub = (RSAKeyParameters)pair.getPublic();
-            RSAPrivateCrtKeyParameters  priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
-
-            return new KeyPair(new JCERSAPublicKey(pub),
-                               new JCERSAPrivateCrtKey(priv));
-        }
-    }
-
-    public static class DH
-        extends JDKKeyPairGenerator
-    {
-        private static Hashtable   params = new Hashtable();
-
-        DHKeyGenerationParameters  param;
-        DHBasicKeyPairGenerator    engine = new DHBasicKeyPairGenerator();
-        int                        strength = 1024;
-        int                        certainty = 20;
-        SecureRandom               random = new SecureRandom();
-        boolean                    initialised = false;
-
-        public DH()
-        {
-            super("DH");
-        }
-
-        public void initialize(
-            int             strength,
-            SecureRandom    random)
-        {
-            this.strength = strength;
-            this.random = random;
-        }
-
-        public void initialize(
-            AlgorithmParameterSpec  params,
-            SecureRandom            random)
-            throws InvalidAlgorithmParameterException
-        {
-            if (!(params instanceof DHParameterSpec))
-            {
-                throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec");
-            }
-            DHParameterSpec     dhParams = (DHParameterSpec)params;
-
-            param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
-
-            engine.init(param);
-            initialised = true;
-        }
-
-        public KeyPair generateKeyPair()
-        {
-            if (!initialised)
-            {
-                // BEGIN android-changed
-                Integer paramStrength = Integer.valueOf(strength);
-                // END android-changed
-
-                if (params.containsKey(paramStrength))
-                {
-                    param = (DHKeyGenerationParameters)params.get(paramStrength);
-                }
-                else
-                {
-                    DHParametersGenerator   pGen = new DHParametersGenerator();
-
-                    pGen.init(strength, certainty, random);
-
-                    param = new DHKeyGenerationParameters(random, pGen.generateParameters());
-
-                    params.put(paramStrength, param);
-                }
-
-                engine.init(param);
-
-                initialised = true;
-            }
-
-            AsymmetricCipherKeyPair pair = engine.generateKeyPair();
-            DHPublicKeyParameters   pub = (DHPublicKeyParameters)pair.getPublic();
-            DHPrivateKeyParameters  priv = (DHPrivateKeyParameters)pair.getPrivate();
-
-            return new KeyPair(new JCEDHPublicKey(pub),
-                               new JCEDHPrivateKey(priv));
-        }
-    }
-
-    public static class DSA
-        extends JDKKeyPairGenerator
-    {
-        DSAKeyGenerationParameters param;
-        DSAKeyPairGenerator        engine = new DSAKeyPairGenerator();
-        int                        strength = 1024;
-        int                        certainty = 20;
-        SecureRandom               random = new SecureRandom();
-        boolean                    initialised = false;
-
-        public DSA()
-        {
-            super("DSA");
-        }
-
-        public void initialize(
-            int             strength,
-            SecureRandom    random)
-        {
-            if (strength < 512 || strength > 1024 || strength % 64 != 0)
-            {
-                throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
-            }
-
-            this.strength = strength;
-            this.random = random;
-        }
-
-        public void initialize(
-            AlgorithmParameterSpec  params,
-            SecureRandom            random)
-            throws InvalidAlgorithmParameterException
-        {
-            if (!(params instanceof DSAParameterSpec))
-            {
-                throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec");
-            }
-            DSAParameterSpec     dsaParams = (DSAParameterSpec)params;
-
-            param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
-
-            engine.init(param);
-            initialised = true;
-        }
-
-        public KeyPair generateKeyPair()
-        {
-            if (!initialised)
-            {
-                DSAParametersGenerator   pGen = new DSAParametersGenerator();
-
-                pGen.init(strength, certainty, random);
-                param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
-                engine.init(param);
-                initialised = true;
-            }
-
-            AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
-            DSAPublicKeyParameters     pub = (DSAPublicKeyParameters)pair.getPublic();
-            DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
-
-            return new KeyPair(new JDKDSAPublicKey(pub),
-                               new JDKDSAPrivateKey(priv));
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class ElGamal
-    //     extends JDKKeyPairGenerator
-    // {
-    //     ElGamalKeyGenerationParameters  param;
-    //     ElGamalKeyPairGenerator         engine = new ElGamalKeyPairGenerator();
-    //     int                             strength = 1024;
-    //     int                             certainty = 20;
-    //     SecureRandom                    random = new SecureRandom();
-    //     boolean                         initialised = false;
-    //
-    //     public ElGamal()
-    //     {
-    //         super("ElGamal");
-    //     }
-    //
-    //     public void initialize(
-    //         int             strength,
-    //         SecureRandom    random)
-    //     {
-    //         this.strength = strength;
-    //         this.random = random;
-    //     }
-    //
-    //     public void initialize(
-    //         AlgorithmParameterSpec  params,
-    //         SecureRandom            random)
-    //         throws InvalidAlgorithmParameterException
-    //     {
-    //         if (!(params instanceof ElGamalParameterSpec) && !(params instanceof DHParameterSpec))
-    //         {
-    //             throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec or an ElGamalParameterSpec");
-    //         }
-    //
-    //         if (params instanceof ElGamalParameterSpec)
-    //         {
-    //             ElGamalParameterSpec     elParams = (ElGamalParameterSpec)params;
-
-    //             param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(elParams.getP(), elParams.getG()));
-    //         }
-    //         else
-    //         {
-    //             DHParameterSpec     dhParams = (DHParameterSpec)params;
-    //
-    //             param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(dhParams.getP(), dhParams.getG(), dhParams.getL()));
-    //         }
-    //
-    //         engine.init(param);
-    //         initialised = true;
-    //     }
-    //
-    //     public KeyPair generateKeyPair()
-    //     {
-    //         if (!initialised)
-    //         {
-    //             ElGamalParametersGenerator   pGen = new ElGamalParametersGenerator();
-    //
-    //             pGen.init(strength, certainty, random);
-    //             param = new ElGamalKeyGenerationParameters(random, pGen.generateParameters());
-    //             engine.init(param);
-    //             initialised = true;
-    //         }
-    //
-    //         AsymmetricCipherKeyPair         pair = engine.generateKeyPair();
-    //         ElGamalPublicKeyParameters      pub = (ElGamalPublicKeyParameters)pair.getPublic();
-    //         ElGamalPrivateKeyParameters     priv = (ElGamalPrivateKeyParameters)pair.getPrivate();
-    //
-    //         return new KeyPair(new JCEElGamalPublicKey(pub),
-    //                            new JCEElGamalPrivateKey(priv));
-    //     }
-    // }
-    // END android-removed
-
-   // BEGIN android-removed
-   //  public static class GOST3410
-   //      extends JDKKeyPairGenerator
-   //  {
-   //      GOST3410KeyGenerationParameters param;
-   //      GOST3410KeyPairGenerator        engine = new GOST3410KeyPairGenerator();
-   //      GOST3410ParameterSpec           gost3410Params;
-   //      int                             strength = 1024;
-   //      SecureRandom                    random = null;
-   //      boolean                         initialised = false;
-   //
-   //      public GOST3410()
-   //      {
-   //          super("GOST3410");
-   //      }
-   //
-   //      public void initialize(
-   //          int             strength,
-   //          SecureRandom    random)
-   //      {
-   //          this.strength = strength;
-   //          this.random = random;
-   //      }
-   //
-   //      private void init(
-   //          GOST3410ParameterSpec gParams,
-   //          SecureRandom          random)
-   //      {
-   //          GOST3410PublicKeyParameterSetSpec spec = gParams.getPublicKeyParameters();
-   //
-   //          param = new GOST3410KeyGenerationParameters(random, new GOST3410Parameters(spec.getP(), spec.getQ(), spec.getA()));
-   //
-   //          engine.init(param);
-   //
-   //          initialised = true;
-   //          gost3410Params = gParams;
-   //      }
-   //
-   //      public void initialize(
-   //          AlgorithmParameterSpec  params,
-   //          SecureRandom            random)
-   //          throws InvalidAlgorithmParameterException
-   //      {
-   //          if (!(params instanceof GOST3410ParameterSpec))
-   //          {
-   //              throw new InvalidAlgorithmParameterException("parameter object not a GOST3410ParameterSpec");
-   //          }
-   //
-   //          init((GOST3410ParameterSpec)params, random);
-   //      }
-   //
-   //      public KeyPair generateKeyPair()
-   //      {
-   //          if (!initialised)
-   //          {
-   //              init(new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()), new SecureRandom());
-   //          }
-   //         
-   //          AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
-   //          GOST3410PublicKeyParameters  pub = (GOST3410PublicKeyParameters)pair.getPublic();
-   //          GOST3410PrivateKeyParameters priv = (GOST3410PrivateKeyParameters)pair.getPrivate();
-   //
-   //          return new KeyPair(new JDKGOST3410PublicKey(pub, gost3410Params), new JDKGOST3410PrivateKey(priv, gost3410Params));
-   //      }
-   // }
-   // END android-removed
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java b/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
index 1c68095..cac736d 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
@@ -54,12 +54,13 @@
 import org.bouncycastle.jce.interfaces.BCKeyStore;
 import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.io.Streams;
+import org.bouncycastle.util.io.TeeOutputStream;
 
 public class JDKKeyStore
     extends KeyStoreSpi
     implements BCKeyStore
 {
-    private static final int    STORE_VERSION = 1;
+    private static final int    STORE_VERSION = 2;
 
     private static final int    STORE_SALT_SIZE = 20;
     private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
@@ -447,7 +448,6 @@
         }
         catch (Exception e)
         {
-
             throw new IOException("Exception creating key: " + e.toString());
         }
     }
@@ -807,13 +807,19 @@
 
         if (version != STORE_VERSION)
         {
-            if (version != 0)
+            if (version != 0 && version != 1)
             {
                 throw new IOException("Wrong version of key store.");
             }
         }
 
-        byte[]      salt = new byte[dIn.readInt()];
+        int saltLength = dIn.readInt();
+        if (saltLength <= 0)
+        {
+            throw new IOException("Invalid salt detected");
+        }
+
+        byte[]      salt = new byte[saltLength];
 
         dIn.readFully(salt);
 
@@ -833,7 +839,18 @@
             PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
             // END android-changed
             pbeGen.init(passKey, salt, iterationCount);
-            CipherParameters macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
+
+            CipherParameters macParams;
+
+            if (version != 2)
+            {
+                macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
+            }
+            else
+            {
+                macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8);
+            }
+
             Arrays.fill(passKey, (byte)0);
 
             hMac.init(macParams);
@@ -884,21 +901,21 @@
 
         // BEGIN android-changed
         HMac                    hMac = new HMac(new OpenSSLDigest.SHA1());
-        MacOutputStream         mOut = new MacOutputStream(dOut, hMac);
+        MacOutputStream         mOut = new MacOutputStream(hMac);
         PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
         // END android-changed
         byte[]                  passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
 
         pbeGen.init(passKey, salt, iterationCount);
 
-        hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
+        hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8));
 
         for (int i = 0; i != passKey.length; i++)
         {
             passKey[i] = 0;
         }
 
-        saveStore(mOut);
+        saveStore(new TeeOutputStream(dOut, mOut));
 
         byte[]  mac = new byte[hMac.getMacSize()];
 
@@ -911,7 +928,7 @@
 
     /**
      * the BouncyCastle store. This wont work with the key tool as the
-     * store is stored encrypteed on disk, so the password is mandatory,
+     * store is stored encrypted on disk, so the password is mandatory,
      * however if you hard drive is in a bad part of town and you absolutely,
      * positively, don't want nobody peeking at your things, this is the
      * one to use, no problem! After all in a Bouncy Castle nothing can
@@ -939,7 +956,7 @@
     
             if (version != STORE_VERSION)
             {
-                if (version != 0)
+                if (version != 0 && version != 1)
                 {
                     throw new IOException("Wrong version of key store.");
                 }
@@ -996,8 +1013,7 @@
                 throw new IOException("KeyStore integrity check failed.");
             }
         }
-    
-    
+
         public void engineStore(OutputStream stream, char[] password) 
             throws IOException
         {
@@ -1017,18 +1033,16 @@
     
             CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
             // BEGIN android-changed
-            DigestOutputStream  dgOut = new DigestOutputStream(cOut, new OpenSSLDigest.SHA1());
+            DigestOutputStream  dgOut = new DigestOutputStream(new OpenSSLDigest.SHA1());
             // END android-changed
-            this.saveStore(dgOut);
     
-            Digest  dig = dgOut.getDigest();
-            byte[]  hash = new byte[dig.getDigestSize()];
+            this.saveStore(new TeeOutputStream(cOut, dgOut));
     
-            dig.doFinal(hash, 0);
-    
-            cOut.write(hash);
+            byte[]  dig = dgOut.getDigest();
+
+            cOut.write(dig);
     
             cOut.close();
         }
-    }    
+    }
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKMessageDigest.java b/src/main/java/org/bouncycastle/jce/provider/JDKMessageDigest.java
deleted file mode 100644
index 0accdc4..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/JDKMessageDigest.java
+++ /dev/null
@@ -1,342 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import java.security.MessageDigest;
-
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.*;
-
-public class JDKMessageDigest
-    extends MessageDigest
-{
-    Digest  digest;
-
-    protected JDKMessageDigest(
-        Digest  digest)
-    {
-        super(digest.getAlgorithmName());
-
-        this.digest = digest;
-    }
-
-    public void engineReset() 
-    {
-        digest.reset();
-    }
-
-    public void engineUpdate(
-        byte    input) 
-    {
-        digest.update(input);
-    }
-
-    public void engineUpdate(
-        byte[]  input,
-        int     offset,
-        int     len) 
-    {
-        digest.update(input, offset, len);
-    }
-
-    public byte[] engineDigest() 
-    {
-        byte[]  digestBytes = new byte[digest.getDigestSize()];
-
-        digest.doFinal(digestBytes, 0);
-
-        return digestBytes;
-    }
-
-    /**
-     * classes that extend directly off us.
-     */
-    static public class SHA1
-        extends JDKMessageDigest
-        implements Cloneable
-    {
-        public SHA1()
-        {
-            super(new SHA1Digest());
-        }
-    
-        public Object clone()
-            throws CloneNotSupportedException
-        {
-            SHA1 d = (SHA1)super.clone();
-            d.digest = new SHA1Digest((SHA1Digest)digest);
-    
-            return d;
-        }
-    }
-    
-    // BEGIN android-removed
-    // static public class SHA224
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public SHA224()
-    //     {
-    //         super(new SHA224Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         SHA224 d = (SHA224)super.clone();
-    //         d.digest = new SHA224Digest((SHA224Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    // END android-removed
-    
-    static public class SHA256
-        extends JDKMessageDigest
-        implements Cloneable
-    {
-        public SHA256()
-        {
-            super(new SHA256Digest());
-        }
-    
-        public Object clone()
-            throws CloneNotSupportedException
-        {
-            SHA256 d = (SHA256)super.clone();
-            d.digest = new SHA256Digest((SHA256Digest)digest);
-    
-            return d;
-        }
-    }
-
-    static public class SHA384
-        extends JDKMessageDigest
-        implements Cloneable
-    {
-        public SHA384()
-        {
-            super(new SHA384Digest());
-        }
-
-        public Object clone()
-            throws CloneNotSupportedException
-        {
-            SHA384 d = (SHA384)super.clone();
-            d.digest = new SHA384Digest((SHA384Digest)digest);
-
-            return d;
-        }
-    }
-
-    static public class SHA512
-        extends JDKMessageDigest
-        implements Cloneable
-    {
-        public SHA512()
-        {
-            super(new SHA512Digest());
-        }
-
-        public Object clone()
-            throws CloneNotSupportedException
-        {
-            SHA512 d = (SHA512)super.clone();
-            d.digest = new SHA512Digest((SHA512Digest)digest);
-
-            return d;
-        }
-    }
-
-    // BEGIN android-removed
-    // static public class MD2
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public MD2()
-    //     {
-    //         super(new MD2Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         MD2 d = (MD2)super.clone();
-    //         d.digest = new MD2Digest((MD2Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //
-    // static public class MD4
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public MD4()
-    //     {
-    //         super(new MD4Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         MD4 d = (MD4)super.clone();
-    //         d.digest = new MD4Digest((MD4Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    // END android-removed
-
-    static public class MD5
-        extends JDKMessageDigest
-        implements Cloneable
-    {
-        public MD5()
-        {
-            super(new MD5Digest());
-        }
-   
-        public Object clone()
-            throws CloneNotSupportedException
-        {
-            MD5 d = (MD5)super.clone();
-            d.digest = new MD5Digest((MD5Digest)digest);
-   
-            return d;
-        }
-    }
-
-    // BEGIN android-removed
-    // static public class RIPEMD128
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public RIPEMD128()
-    //     {
-    //         super(new RIPEMD128Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         RIPEMD128 d = (RIPEMD128)super.clone();
-    //         d.digest = new RIPEMD128Digest((RIPEMD128Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //
-    // static public class RIPEMD160
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public RIPEMD160()
-    //     {
-    //         super(new RIPEMD160Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         RIPEMD160 d = (RIPEMD160)super.clone();
-    //         d.digest = new RIPEMD160Digest((RIPEMD160Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //   
-    // static public class RIPEMD256
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public RIPEMD256()
-    //     {
-    //         super(new RIPEMD256Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         RIPEMD256 d = (RIPEMD256)super.clone();
-    //         d.digest = new RIPEMD256Digest((RIPEMD256Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //   
-    // static public class RIPEMD320
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public RIPEMD320()
-    //     {
-    //         super(new RIPEMD320Digest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         RIPEMD320 d = (RIPEMD320)super.clone();
-    //         d.digest = new RIPEMD320Digest((RIPEMD320Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //   
-    // static public class Tiger
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public Tiger()
-    //     {
-    //         super(new TigerDigest());
-    //     }
-    //
-    //     public Object clone()
-    //         throws CloneNotSupportedException
-    //     {
-    //         Tiger d = (Tiger)super.clone();
-    //         d.digest = new TigerDigest((TigerDigest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //   
-    // static public class GOST3411
-    //     extends JDKMessageDigest
-    //     implements Cloneable
-    // {
-    //     public GOST3411()
-    //     {
-    //         super(new GOST3411Digest());
-    //     }
-    //   
-    //     public Object clone()
-    //     throws CloneNotSupportedException
-    //     {
-    //         GOST3411 d = (GOST3411)super.clone();
-    //         d.digest = new GOST3411Digest((GOST3411Digest)digest);
-    //
-    //         return d;
-    //     }
-    // }
-    //   
-    // static public class Whirlpool
-    //    extends JDKMessageDigest
-    //    implements Cloneable
-    // {
-    //     public Whirlpool()
-    //     {
-    //         super(new WhirlpoolDigest());
-    //     }
-    //       
-    //     public Object clone()
-    //     throws CloneNotSupportedException
-    //     {
-    //         Whirlpool d = (Whirlpool)super.clone();
-    //         d.digest = new WhirlpoolDigest((WhirlpoolDigest)digest);
-    //           
-    //         return d;
-    //     }
-    // }
-    // END android-removed
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java b/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
index 9707b05..2d9f683 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
@@ -8,6 +8,8 @@
 import java.io.OutputStream;
 import java.security.Key;
 import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
 import java.security.KeyStoreException;
 import java.security.KeyStoreSpi;
 import java.security.NoSuchAlgorithmException;
@@ -17,8 +19,6 @@
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
-import java.security.KeyStore.LoadStoreParameter;
-import java.security.KeyStore.ProtectionParameter;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
@@ -36,19 +36,19 @@
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.PBEParameterSpec;
 
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.BERConstructedOctetString;
 import org.bouncycastle.asn1.BEROutputStream;
 import org.bouncycastle.asn1.DERBMPString;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DEROutputStream;
 import org.bouncycastle.asn1.DERSequence;
@@ -70,6 +70,7 @@
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509Extensions;
 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
 import org.bouncycastle.jce.interfaces.BCKeyStore;
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
 import org.bouncycastle.util.Arrays;
@@ -111,8 +112,8 @@
 
     // use of final causes problems with JDK 1.2 compiler
     private CertificateFactory  certFact;
-    private DERObjectIdentifier keyAlgorithm;
-    private DERObjectIdentifier certAlgorithm;
+    private ASN1ObjectIdentifier keyAlgorithm;
+    private ASN1ObjectIdentifier certAlgorithm;
 
     private class CertId
     {
@@ -156,8 +157,8 @@
 
     public JDKPKCS12KeyStore(
         Provider provider,
-        DERObjectIdentifier keyAlgorithm,
-        DERObjectIdentifier certAlgorithm)
+        ASN1ObjectIdentifier keyAlgorithm,
+        ASN1ObjectIdentifier certAlgorithm)
     {
         this.keyAlgorithm = keyAlgorithm;
         this.certAlgorithm = certAlgorithm;
@@ -185,7 +186,7 @@
         try
         {
             SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
-                (ASN1Sequence) ASN1Object.fromByteArray(pubKey.getEncoded()));
+                (ASN1Sequence) ASN1Primitive.fromByteArray(pubKey.getEncoded()));
 
             return new SubjectKeyIdentifier(info);
         }
@@ -369,7 +370,7 @@
                         byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
                         aIn = new ASN1InputStream(authBytes);
 
-                        AuthorityKeyIdentifier id = new AuthorityKeyIdentifier((ASN1Sequence)aIn.readObject());
+                        AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance((ASN1Sequence)aIn.readObject());
                         if (id.getKeyIdentifier() != null)
                         {
                             nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
@@ -567,8 +568,8 @@
         boolean               wrongPKCS12Zero)
         throws IOException
     {
-        String              algorithm = algId.getObjectId().getId();
-        PKCS12PBEParams     pbeParams = new PKCS12PBEParams((ASN1Sequence)algId.getParameters());
+        String              algorithm = algId.getAlgorithm().getId();
+        PKCS12PBEParams     pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
 
         PBEKeySpec          pbeSpec = new PBEKeySpec(password);
         PrivateKey          out;
@@ -583,7 +584,7 @@
 
             SecretKey           k = keyFact.generateSecret(pbeSpec);
             
-            ((JCEPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+            ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
 
             Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
 
@@ -640,8 +641,8 @@
         byte[]                data)
         throws IOException
     {
-        String          algorithm = algId.getObjectId().getId();
-        PKCS12PBEParams pbeParams = new PKCS12PBEParams((ASN1Sequence)algId.getParameters());
+        String          algorithm = algId.getAlgorithm().getId();
+        PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
         PBEKeySpec      pbeSpec = new PBEKeySpec(password);
 
         try
@@ -650,7 +651,7 @@
             PBEParameterSpec defParams = new PBEParameterSpec(
                 pbeParams.getIV(),
                 pbeParams.getIterations().intValue());
-            JCEPBEKey        key = (JCEPBEKey) keyFact.generateSecret(pbeSpec);
+            BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
 
             key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
 
@@ -695,7 +696,7 @@
 
         ASN1InputStream bIn = new ASN1InputStream(bufIn);
         ASN1Sequence    obj = (ASN1Sequence)bIn.readObject();
-        Pfx             bag = new Pfx(obj);
+        Pfx             bag = Pfx.getInstance(obj);
         ContentInfo     info = bag.getAuthSafe();
         Vector          chain = new Vector();
         boolean         unmarkedKey = false;
@@ -751,7 +752,7 @@
         {
             bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
 
-            AuthenticatedSafe   authSafe = new AuthenticatedSafe((ASN1Sequence)bIn.readObject());
+            AuthenticatedSafe   authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
             ContentInfo[]       c = authSafe.getContentInfo();
 
             for (int i = 0; i != c.length; i++)
@@ -763,10 +764,10 @@
 
                     for (int j = 0; j != seq.size(); j++)
                     {
-                        SafeBag b = new SafeBag((ASN1Sequence)seq.getObjectAt(j));
+                        SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
                         if (b.getBagId().equals(pkcs8ShroudedKeyBag))
                         {
-                            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo((ASN1Sequence)b.getBagValue());
+                            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
                             PrivateKey              privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
 
                             //
@@ -782,19 +783,19 @@
                                 while (e.hasMoreElements())
                                 {
                                     ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
-                                    DERObjectIdentifier     aOid = (DERObjectIdentifier)sq.getObjectAt(0);
+                                    ASN1ObjectIdentifier     aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
                                     ASN1Set                 attrSet = (ASN1Set)sq.getObjectAt(1);
-                                    DERObject               attr = null;
+                                    ASN1Primitive               attr = null;
     
                                     if (attrSet.size() > 0)
                                     {
-                                        attr = (DERObject)attrSet.getObjectAt(0);
+                                        attr = (ASN1Primitive)attrSet.getObjectAt(0);
 
-                                        DEREncodable existing = bagAttr.getBagAttribute(aOid);
+                                        ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
                                         if (existing != null)
                                         {
                                             // OK, but the value has to be the same
-                                            if (!existing.getDERObject().equals(attr))
+                                            if (!existing.toASN1Primitive().equals(attr))
                                             {
                                                 throw new IOException(
                                                     "attempt to add existing attribute with different value");
@@ -850,14 +851,14 @@
                 }
                 else if (c[i].getContentType().equals(encryptedData))
                 {
-                    EncryptedData d = new EncryptedData((ASN1Sequence)c[i].getContent());
+                    EncryptedData d = EncryptedData.getInstance(c[i].getContent());
                     byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
                         password, wrongPKCS12Zero, d.getContent().getOctets());
-                    ASN1Sequence seq = (ASN1Sequence) ASN1Object.fromByteArray(octets);
+                    ASN1Sequence seq = (ASN1Sequence) ASN1Primitive.fromByteArray(octets);
 
                     for (int j = 0; j != seq.size(); j++)
                     {
-                        SafeBag b = new SafeBag((ASN1Sequence)seq.getObjectAt(j));
+                        SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
                         
                         if (b.getBagId().equals(certBag))
                         {
@@ -865,7 +866,7 @@
                         }
                         else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
                         {
-                            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo((ASN1Sequence)b.getBagValue());
+                            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
                             PrivateKey              privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
 
                             //
@@ -879,19 +880,19 @@
                             while (e.hasMoreElements())
                             {
                                 ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
-                                DERObjectIdentifier     aOid = (DERObjectIdentifier)sq.getObjectAt(0);
+                                ASN1ObjectIdentifier     aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
                                 ASN1Set                 attrSet= (ASN1Set)sq.getObjectAt(1);
-                                DERObject               attr = null;
+                                ASN1Primitive               attr = null;
 
                                 if (attrSet.size() > 0)
                                 {
-                                    attr = (DERObject)attrSet.getObjectAt(0);
+                                    attr = (ASN1Primitive)attrSet.getObjectAt(0);
 
-                                    DEREncodable existing = bagAttr.getBagAttribute(aOid);
+                                    ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
                                     if (existing != null)
                                     {
                                         // OK, but the value has to be the same
-                                        if (!existing.getDERObject().equals(attr))
+                                        if (!existing.toASN1Primitive().equals(attr))
                                         {
                                             throw new IOException(
                                                 "attempt to add existing attribute with different value");
@@ -927,8 +928,8 @@
                         }
                         else if (b.getBagId().equals(keyBag))
                         {
-                            org.bouncycastle.asn1.pkcs.PrivateKeyInfo pIn = new org.bouncycastle.asn1.pkcs.PrivateKeyInfo((ASN1Sequence)b.getBagValue());
-                            PrivateKey              privKey = JDKKeyFactory.createPrivateKeyFromPrivateKeyInfo(pIn);
+                            org.bouncycastle.asn1.pkcs.PrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.PrivateKeyInfo((ASN1Sequence)b.getBagValue());
+                            PrivateKey     privKey = BouncyCastleProvider.getPrivateKey(kInfo);
 
                             //
                             // set the attributes on the key
@@ -941,19 +942,19 @@
                             while (e.hasMoreElements())
                             {
                                 ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
-                                DERObjectIdentifier     aOid = (DERObjectIdentifier)sq.getObjectAt(0);
+                                ASN1ObjectIdentifier     aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
                                 ASN1Set                 attrSet = (ASN1Set)sq.getObjectAt(1);
-                                DERObject   attr = null;
+                                ASN1Primitive   attr = null;
 
                                 if (attrSet.size() > 0)
                                 {
-                                    attr = (DERObject)attrSet.getObjectAt(0);
+                                    attr = (ASN1Primitive)attrSet.getObjectAt(0);
 
-                                    DEREncodable existing = bagAttr.getBagAttribute(aOid);
+                                    ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
                                     if (existing != null)
                                     {
                                         // OK, but the value has to be the same
-                                        if (!existing.getDERObject().equals(attr))
+                                        if (!existing.toASN1Primitive().equals(attr))
                                         {
                                             throw new IOException(
                                                 "attempt to add existing attribute with different value");
@@ -1009,7 +1010,7 @@
         for (int i = 0; i != chain.size(); i++)
         {
             SafeBag     b = (SafeBag)chain.elementAt(i);
-            CertBag     cb = new CertBag((ASN1Sequence)b.getBagValue());
+            CertBag     cb = CertBag.getInstance(b.getBagValue());
 
             if (!cb.getCertId().equals(x509Certificate))
             {
@@ -1041,19 +1042,19 @@
                 while (e.hasMoreElements())
                 {
                     ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
-                    DERObjectIdentifier     oid = (DERObjectIdentifier)sq.getObjectAt(0);
-                    DERObject               attr = (DERObject)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+                    ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+                    ASN1Primitive               attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
                     PKCS12BagAttributeCarrier   bagAttr = null;
 
                     if (cert instanceof PKCS12BagAttributeCarrier)
                     {
                         bagAttr = (PKCS12BagAttributeCarrier)cert;
 
-                        DEREncodable existing = bagAttr.getBagAttribute(oid);
+                        ASN1Encodable existing = bagAttr.getBagAttribute(oid);
                         if (existing != null)
                         {
                             // OK, but the value has to be the same
-                            if (!existing.getDERObject().equals(attr))
+                            if (!existing.toASN1Primitive().equals(attr))
                             {
                                 throw new IOException(
                                     "attempt to add existing attribute with different value");
@@ -1174,7 +1175,7 @@
             PrivateKey              privKey = (PrivateKey)keys.get(name);
             PKCS12PBEParams         kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
             byte[]                  kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
-            AlgorithmIdentifier     kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.getDERObject());
+            AlgorithmIdentifier     kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
             org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
             boolean                 attrSet = false;
             ASN1EncodableVector     kName = new ASN1EncodableVector();
@@ -1205,7 +1206,7 @@
 
                 while (e.hasMoreElements())
                 {
-                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
                     ASN1EncodableVector  kSeq = new ASN1EncodableVector();
 
                     kSeq.add(oid);
@@ -1238,11 +1239,11 @@
                 kName.add(new DERSequence(kSeq));
             }
 
-            SafeBag                 kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.getDERObject(), new DERSet(kName));
+            SafeBag                 kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
             keyS.add(kBag);
         }
 
-        byte[]                    keySEncoded = new DERSequence(keyS).getDEREncoded();
+        byte[]                    keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
         BERConstructedOctetString keyString = new BERConstructedOctetString(keySEncoded);
 
         //
@@ -1254,7 +1255,7 @@
 
         ASN1EncodableVector  certSeq = new ASN1EncodableVector();
         PKCS12PBEParams         cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
-        AlgorithmIdentifier     cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.getDERObject());
+        AlgorithmIdentifier     cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
         Hashtable               doneCerts = new Hashtable();
 
         Enumeration cs = keys.keys();
@@ -1294,7 +1295,7 @@
 
                     while (e.hasMoreElements())
                     {
-                        DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
                         ASN1EncodableVector fSeq = new ASN1EncodableVector();
 
                         fSeq.add(oid);
@@ -1321,7 +1322,7 @@
                     fName.add(new DERSequence(fSeq));
                 }
 
-                SafeBag sBag = new SafeBag(certBag, cBag.getDERObject(), new DERSet(fName));
+                SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
 
                 certSeq.add(sBag);
 
@@ -1368,7 +1369,7 @@
 
                     while (e.hasMoreElements())
                     {
-                        DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
 
                         // a certificate not immediately linked to a key doesn't require
                         // a localKeyID and will confuse some PKCS12 implementations.
@@ -1399,7 +1400,7 @@
                     fName.add(new DERSequence(fSeq));
                 }
 
-                SafeBag sBag = new SafeBag(certBag, cBag.getDERObject(), new DERSet(fName));
+                SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
 
                 certSeq.add(sBag);
 
@@ -1436,7 +1437,7 @@
 
                     while (e.hasMoreElements())
                     {
-                        DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
 
                         // a certificate not immediately linked to a key doesn't require
                         // a localKeyID and will confuse some PKCS12 implementations.
@@ -1455,7 +1456,7 @@
                     }
                 }
 
-                SafeBag sBag = new SafeBag(certBag, cBag.getDERObject(), new DERSet(fName));
+                SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
 
                 certSeq.add(sBag);
             }
@@ -1465,14 +1466,14 @@
             }
         }
 
-        byte[]          certSeqEncoded = new DERSequence(certSeq).getDEREncoded();
+        byte[]          certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
         byte[]          certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
         EncryptedData   cInfo = new EncryptedData(data, cAlgId, new BERConstructedOctetString(certBytes));
 
         ContentInfo[] info = new ContentInfo[]
         {
             new ContentInfo(data, keyString),
-            new ContentInfo(encryptedData, cInfo.getDERObject())
+            new ContentInfo(encryptedData, cInfo.toASN1Primitive())
         };
 
         AuthenticatedSafe   auth = new AuthenticatedSafe(info);
@@ -1540,7 +1541,7 @@
     }
 
     private static byte[] calculatePbeMac(
-        DERObjectIdentifier oid,
+        ASN1ObjectIdentifier oid,
         byte[]              salt,
         int                 itCount,
         char[]              password,
@@ -1551,7 +1552,7 @@
         SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
         PBEParameterSpec    defParams = new PBEParameterSpec(salt, itCount);
         PBEKeySpec          pbeSpec = new PBEKeySpec(password);
-        JCEPBEKey           key = (JCEPBEKey) keyFact.generateSecret(pbeSpec);
+        BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
         key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
 
         Mac mac = Mac.getInstance(oid.getId(), bcProvider);
@@ -1565,7 +1566,7 @@
     {
         public BCPKCS12KeyStore()
         {
-            super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbewithSHAAnd40BitRC2_CBC);
+            super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
         }
     }
 
@@ -1584,7 +1585,7 @@
     // {
     //     public DefPKCS12KeyStore()
     //     {
-    //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbewithSHAAnd40BitRC2_CBC);
+    //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
     //     }
     // }
     //
@@ -1605,7 +1606,9 @@
 
         public void put(String key, Object value)
         {
+            // BEGIN android-changed
             String lower = (key == null) ? null : Strings.toLowerCase(key);
+            // END android-changed
             String k = (String)keys.get(lower);
             if (k != null)
             {
diff --git a/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java b/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java
index 6f33cfe..04718ef 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java
@@ -1,13 +1,13 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.util.encoders.Base64;
-
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.util.encoders.Base64;
+
 public class PEMUtil
 {
     private final String _header1;
@@ -80,7 +80,7 @@
 
         if (pemBuf.length() != 0)
         {
-            DERObject o = new ASN1InputStream(Base64.decode(pemBuf.toString())).readObject();
+            ASN1Primitive o = new ASN1InputStream(Base64.decode(pemBuf.toString())).readObject();
             if (!(o instanceof ASN1Sequence))
             {
                 throw new IOException("malformed PEM data encountered");
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
index 6f59ffc..af764f3 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -16,7 +16,6 @@
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -24,7 +23,7 @@
 
 import javax.security.auth.x500.X500Principal;
 
-import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
@@ -242,7 +241,7 @@
                     "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
         }
         DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
-        DEREncodable workingPublicKeyParameters = workingAlgId.getParameters();
+        ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
 
         //
         // (k)
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java b/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
index 0af311f..ddf7462 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
@@ -1,13 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1OctetString;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralSubtree;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.Strings;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -17,6 +9,14 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralSubtree;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
 public class PKIXNameConstraintValidator
 {
     private Set excludedSubtreesDN = new HashSet();
@@ -136,7 +136,7 @@
         for (Iterator it = dns.iterator(); it.hasNext();)
         {
             ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it
-                .next()).getBase().getName().getDERObject());
+                .next()).getBase().getName().toASN1Primitive());
             if (permitted == null)
             {
                 if (dn != null)
@@ -1470,7 +1470,7 @@
                 break;
             case 4:
                 checkPermittedDN(ASN1Sequence.getInstance(name.getName()
-                    .getDERObject()));
+                    .toASN1Primitive()));
                 break;
             case 6:
                 checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
@@ -1505,7 +1505,7 @@
                 break;
             case 4:
                 checkExcludedDN(ASN1Sequence.getInstance(name.getName()
-                    .getDERObject()));
+                    .toASN1Primitive()));
                 break;
             case 6:
                 checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
@@ -1620,7 +1620,7 @@
                 break;
             case 4:
                 excludedSubtreesDN = unionDN(excludedSubtreesDN,
-                    (ASN1Sequence)base.getName().getDERObject());
+                    (ASN1Sequence)base.getName().toASN1Primitive());
                 break;
             case 6:
                 excludedSubtreesURI = unionURI(excludedSubtreesURI,
diff --git a/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java b/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
deleted file mode 100644
index 6060ad4..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.Permission;
-
-import org.bouncycastle.jce.ProviderConfigurationPermission;
-import org.bouncycastle.jce.interfaces.ConfigurableProvider;
-import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-import org.bouncycastle.jce.spec.ECParameterSpec;
-
-public class ProviderUtil
-{
-    private static final long  MAX_MEMORY = Runtime.getRuntime().maxMemory();
-
-    private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
-                                                   BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
-    private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
-                                                   BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
-
-    private static ThreadLocal threadSpec = new ThreadLocal();
-    private static volatile ECParameterSpec ecImplicitCaParams;
-
-    static void setParameter(String parameterName, Object parameter)
-    {
-        SecurityManager securityManager = System.getSecurityManager();
-
-        if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
-        {
-            ECParameterSpec curveSpec;
-
-            if (securityManager != null)
-            {
-                securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
-            }
-
-            if (parameter instanceof ECParameterSpec || parameter == null)
-            {
-                curveSpec = (ECParameterSpec)parameter;
-            }
-            else  // assume java.security.spec
-            {
-                curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
-            }
-
-            if (curveSpec == null)
-            {
-                threadSpec.remove();
-            }
-            else
-            {
-                threadSpec.set(curveSpec);
-            }
-        }
-        else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
-        {
-            if (securityManager != null)
-            {
-                securityManager.checkPermission(BC_EC_PERMISSION);
-            }
-
-            if (parameter instanceof ECParameterSpec || parameter == null)
-            {
-                ecImplicitCaParams = (ECParameterSpec)parameter;
-            }
-            else  // assume java.security.spec
-            {
-                ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
-            }
-        }
-    }
-
-    public static ECParameterSpec getEcImplicitlyCa()
-    {
-        ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
-
-        if (spec != null)
-        {
-            return spec;
-        }
-
-        return ecImplicitCaParams;
-    }
-
-    static int getReadLimit(InputStream in)
-        throws IOException
-    {
-        if (in instanceof ByteArrayInputStream)
-        {
-            return in.available();
-        }
-
-        if (MAX_MEMORY > Integer.MAX_VALUE)
-        {
-            return Integer.MAX_VALUE;
-        }
-
-        return (int)MAX_MEMORY;
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
index ef3baaa..7357894 100644
--- a/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
+++ b/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -28,13 +28,13 @@
 
 import javax.security.auth.x500.X500Principal;
 
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.BasicConstraints;
@@ -136,7 +136,7 @@
                                 .getEncoded())).getObjects();
                         while (e.hasMoreElements())
                         {
-                            vec.add((DEREncodable)e.nextElement());
+                            vec.add((ASN1Encodable)e.nextElement());
                         }
                     }
                     catch (IOException e)
@@ -179,11 +179,11 @@
                         }
                         for (int j = 0; j < genNames.length; j++)
                         {
-                            Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().getDERObject()).getObjects();
+                            Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects();
                             ASN1EncodableVector vec = new ASN1EncodableVector();
                             while (e.hasMoreElements())
                             {
-                                vec.add((DEREncodable)e.nextElement());
+                                vec.add((ASN1Encodable)e.nextElement());
                             }
                             vec.add(dpName.getName());
                             genNames[j] = new GeneralName(new X509Name(new DERSequence(vec)));
@@ -285,7 +285,7 @@
         X509CRL crl)
         throws AnnotatedException
     {
-        DERObject idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+        ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
         boolean isIndirect = false;
         if (idp != null)
         {
@@ -306,7 +306,7 @@
                 {
                     try
                     {
-                        if (Arrays.areEqual(genNames[j].getName().getDERObject().getEncoded(), issuerBytes))
+                        if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes))
                         {
                             matchIssuer = true;
                         }
@@ -359,8 +359,7 @@
         // (d) (1)
         if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null)
         {
-            return new ReasonsMask(dp.getReasons().intValue()).intersect(new ReasonsMask(idp.getOnlySomeReasons()
-                .intValue()));
+            return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
         }
         // (d) (4)
         if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null)
@@ -370,9 +369,9 @@
         // (d) (2) and (d)(3)
         return (dp.getReasons() == null
             ? ReasonsMask.allReasons
-            : new ReasonsMask(dp.getReasons().intValue())).intersect(idp == null
+            : new ReasonsMask(dp.getReasons())).intersect(idp == null
             ? ReasonsMask.allReasons
-            : new ReasonsMask(idp.getOnlySomeReasons().intValue()));
+            : new ReasonsMask(idp.getOnlySomeReasons()));
 
     }
 
@@ -787,7 +786,7 @@
             }
 
             // (c) (3)
-            DERObject completeKeyIdentifier = null;
+            ASN1Primitive completeKeyIdentifier = null;
             try
             {
                 completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
@@ -799,7 +798,7 @@
                     "Authority key identifier extension could not be extracted from complete CRL.", e);
             }
 
-            DERObject deltaKeyIdentifier = null;
+            ASN1Primitive deltaKeyIdentifier = null;
             try
             {
                 deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
@@ -1656,7 +1655,7 @@
                 RFC3280CertPathUtilities.NAME_CONSTRAINTS));
             if (ncSeq != null)
             {
-                nc = new NameConstraints(ncSeq);
+                nc = NameConstraints.getInstance(ncSeq);
             }
         }
         catch (Exception e)
@@ -1975,7 +1974,7 @@
                  * omitted and a distribution point name of the certificate
                  * issuer.
                  */
-                DERObject issuer = null;
+                ASN1Primitive issuer = null;
                 try
                 {
                     issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded())
diff --git a/src/main/java/org/bouncycastle/jce/provider/RSAUtil.java b/src/main/java/org/bouncycastle/jce/provider/RSAUtil.java
deleted file mode 100644
index 0d99117..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/RSAUtil.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.bouncycastle.jce.provider;
-
-import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
-import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
-
-/**
- * utility class for converting java.security RSA objects into their
- * org.bouncycastle.crypto counterparts.
- */
-class RSAUtil
-{
-    static boolean isRsaOid(
-        DERObjectIdentifier algOid)
-    {
-        return algOid.equals(PKCSObjectIdentifiers.rsaEncryption)
-            || algOid.equals(X509ObjectIdentifiers.id_ea_rsa)
-            || algOid.equals(PKCSObjectIdentifiers.id_RSASSA_PSS)
-            || algOid.equals(PKCSObjectIdentifiers.id_RSAES_OAEP);
-    }
-    
-    static RSAKeyParameters generatePublicKeyParameter(
-        RSAPublicKey    key)
-    {
-        return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
-
-    }
-
-    static RSAKeyParameters generatePrivateKeyParameter(
-        RSAPrivateKey    key)
-    {
-        if (key instanceof RSAPrivateCrtKey)
-        {
-            RSAPrivateCrtKey    k = (RSAPrivateCrtKey)key;
-
-            return new RSAPrivateCrtKeyParameters(k.getModulus(),
-                k.getPublicExponent(), k.getPrivateExponent(),
-                k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(),                            k.getPrimeExponentQ(), k.getCrtCoefficient());
-        }
-        else
-        {
-            RSAPrivateKey    k = key;
-
-            return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java b/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java
index aeb4892..04f5a06 100644
--- a/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java
+++ b/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java
@@ -15,7 +15,12 @@
      * 
      * @param reasons The reasons.
      */
-    ReasonsMask(int reasons)
+    ReasonsMask(ReasonFlags reasons)
+    {
+        _reasons = reasons.intValue();
+    }
+
+    private ReasonsMask(int reasons)
     {
         _reasons = reasons;
     }
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
index 1a073e0..da7ee11 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
@@ -11,18 +11,19 @@
 
 import javax.security.auth.x500.X500Principal;
 
-import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.DEREnumerated;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.CRLReason;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
 import org.bouncycastle.asn1.x509.GeneralName;
 import org.bouncycastle.asn1.x509.GeneralNames;
 import org.bouncycastle.asn1.x509.TBSCertList;
 import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
 import org.bouncycastle.x509.extension.X509ExtensionUtil;
 
 /**
@@ -35,17 +36,14 @@
 {
     private TBSCertList.CRLEntry c;
 
-    private boolean isIndirect;
-
-    private X500Principal previousCertificateIssuer;
-    private X500Principal certificateIssuer;
+    private X500Name certificateIssuer;
     private int           hashValue;
     private boolean       isHashValueSet;
 
     public X509CRLEntryObject(TBSCertList.CRLEntry c)
     {
         this.c = c;
-        this.certificateIssuer = loadCertificateIssuer();
+        this.certificateIssuer = null;
     }
 
     /**
@@ -68,17 +66,15 @@
     public X509CRLEntryObject(
         TBSCertList.CRLEntry c,
         boolean isIndirect,
-        X500Principal previousCertificateIssuer)
+        X500Name previousCertificateIssuer)
     {
         this.c = c;
-        this.isIndirect = isIndirect;
-        this.previousCertificateIssuer = previousCertificateIssuer;
-        this.certificateIssuer = loadCertificateIssuer();
+        this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
     }
 
     /**
      * Will return true if any extensions are present and marked as critical as
-     * we currently dont handle any extensions!
+     * we currently don't handle any extensions!
      */
     public boolean hasUnsupportedCriticalExtension()
     {
@@ -87,14 +83,14 @@
         return extns != null && !extns.isEmpty();
     }
 
-    private X500Principal loadCertificateIssuer()
+    private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
     {
         if (!isIndirect)
         {
             return null;
         }
 
-        byte[] ext = getExtensionValue(X509Extensions.CertificateIssuer.getId());
+        byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId());
         if (ext == null)
         {
             return previousCertificateIssuer;
@@ -108,7 +104,7 @@
             {
                 if (names[i].getTagNo() == GeneralName.directoryName)
                 {
-                    return new X500Principal(names[i].getName().getDERObject().getDEREncoded());
+                    return X500Name.getInstance(names[i].getName());
                 }
             }
             return null;
@@ -121,12 +117,23 @@
 
     public X500Principal getCertificateIssuer()
     {
-        return certificateIssuer;
+        if (certificateIssuer == null)
+        {
+            return null;
+        }
+        try
+        {
+            return new X500Principal(certificateIssuer.getEncoded());
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
     }
 
     private Set getExtensionOIDs(boolean critical)
     {
-        X509Extensions extensions = c.getExtensions();
+        Extensions extensions = c.getExtensions();
 
         if (extensions != null)
         {
@@ -135,8 +142,8 @@
 
             while (e.hasMoreElements())
             {
-                DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement();
-                X509Extension ext = extensions.getExtension(oid);
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+                Extension ext = extensions.getExtension(oid);
 
                 if (critical == ext.isCritical())
                 {
@@ -162,17 +169,17 @@
 
     public byte[] getExtensionValue(String oid)
     {
-        X509Extensions exts = c.getExtensions();
+        Extensions exts = c.getExtensions();
 
         if (exts != null)
         {
-            X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+            Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
 
             if (ext != null)
             {
                 try
                 {
-                    return ext.getValue().getEncoded();
+                    return ext.getExtnValue().getEncoded();
                 }
                 catch (Exception e)
                 {
@@ -204,7 +211,7 @@
     {
         try
         {
-            return c.getEncoded(ASN1Encodable.DER);
+            return c.getEncoded(ASN1Encoding.DER);
         }
         catch (IOException e)
         {
@@ -236,7 +243,7 @@
         buf.append("       revocationDate: ").append(this.getRevocationDate()).append(nl);
         buf.append("       certificateIssuer: ").append(this.getCertificateIssuer()).append(nl);
 
-        X509Extensions extensions = c.getExtensions();
+        Extensions extensions = c.getExtensions();
 
         if (extensions != null)
         {
@@ -247,22 +254,22 @@
 
                 while (e.hasMoreElements())
                 {
-                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
-                    X509Extension ext = extensions.getExtension(oid);
-                    if (ext.getValue() != null)
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension ext = extensions.getExtension(oid);
+                    if (ext.getExtnValue() != null)
                     {
-                        byte[]                  octs = ext.getValue().getOctets();
+                        byte[]                  octs = ext.getExtnValue().getOctets();
                         ASN1InputStream dIn = new ASN1InputStream(octs);
                         buf.append("                       critical(").append(ext.isCritical()).append(") ");
                         try
                         {
-                            if (oid.equals(X509Extensions.ReasonCode))
+                            if (oid.equals(X509Extension.reasonCode))
                             {
-                                buf.append(new CRLReason(DEREnumerated.getInstance(dIn.readObject()))).append(nl);
+                                buf.append(CRLReason.getInstance(DEREnumerated.getInstance(dIn.readObject()))).append(nl);
                             }
-                            else if (oid.equals(X509Extensions.CertificateIssuer))
+                            else if (oid.equals(X509Extension.certificateIssuer))
                             {
-                                buf.append("Certificate issuer: ").append(new GeneralNames((ASN1Sequence)dIn.readObject())).append(nl);
+                                buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
                             }
                             else 
                             {
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
index 956c58b..4c87114 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -1,6 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
@@ -12,6 +11,7 @@
 import java.security.SignatureException;
 import java.security.cert.CRLException;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509CRL;
 import java.security.cert.X509CRLEntry;
 import java.security.cert.X509Certificate;
@@ -25,19 +25,20 @@
 import javax.security.auth.x500.X500Principal;
 
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1OutputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.CRLDistPoint;
 import org.bouncycastle.asn1.x509.CRLNumber;
 import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.GeneralNames;
 import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
 import org.bouncycastle.asn1.x509.TBSCertList;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
 import org.bouncycastle.jce.X509Principal;
 import org.bouncycastle.util.encoders.Hex;
 import org.bouncycastle.x509.extension.X509ExtensionUtil;
@@ -59,6 +60,22 @@
     private byte[] sigAlgParams;
     private boolean isIndirect;
 
+    static boolean isIndirectCRL(X509CRL crl)
+        throws CRLException
+    {
+        try
+        {
+            byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+            return idp != null
+                && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+        }
+        catch (Exception e)
+        {
+            throw new ExtCRLException(
+                    "Exception reading IssuingDistributionPoint", e);
+        }
+    }
+
     public X509CRLObject(
         CertificateList c)
         throws CRLException
@@ -71,14 +88,14 @@
             
             if (c.getSignatureAlgorithm().getParameters() != null)
             {
-                this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).getDEREncoded();
+                this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
             }
             else
             {
                 this.sigAlgParams = null;
             }
 
-            this.isIndirect = isIndirectCRL();
+            this.isIndirect = isIndirectCRL(this);
         }
         catch (Exception e)
         {
@@ -109,7 +126,7 @@
     {
         if (this.getVersion() == 2)
         {
-            X509Extensions extensions = c.getTBSCertList().getExtensions();
+            Extensions extensions = c.getTBSCertList().getExtensions();
 
             if (extensions != null)
             {
@@ -118,8 +135,8 @@
 
                 while (e.hasMoreElements())
                 {
-                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
-                    X509Extension ext = extensions.getExtension(oid);
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension ext = extensions.getExtension(oid);
 
                     if (critical == ext.isCritical())
                     {
@@ -146,17 +163,17 @@
 
     public byte[] getExtensionValue(String oid)
     {
-        X509Extensions exts = c.getTBSCertList().getExtensions();
+        Extensions exts = c.getTBSCertList().getExtensions();
 
         if (exts != null)
         {
-            X509Extension   ext = exts.getExtension(new DERObjectIdentifier(oid));
+            Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
 
             if (ext != null)
             {
                 try
                 {
-                    return ext.getValue().getEncoded();
+                    return ext.getExtnValue().getEncoded();
                 }
                 catch (Exception e)
                 {
@@ -173,7 +190,7 @@
     {
         try
         {
-            return c.getEncoded(ASN1Encodable.DER);
+            return c.getEncoded(ASN1Encoding.DER);
         }
         catch (IOException e)
         {
@@ -197,10 +214,20 @@
             throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
         }
 
-        Signature sig = Signature.getInstance(getSigAlgName(), sigProvider);
+        Signature sig;
+
+        if (sigProvider != null)
+        {
+            sig = Signature.getInstance(getSigAlgName(), sigProvider);
+        }
+        else
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
 
         sig.initVerify(key);
         sig.update(this.getTBSCertList());
+
         if (!sig.verify(this.getSignature()))
         {
             throw new SignatureException("CRL does not verify with supplied public key.");
@@ -209,24 +236,19 @@
 
     public int getVersion()
     {
-        return c.getVersion();
+        return c.getVersionNumber();
     }
 
     public Principal getIssuerDN()
     {
-        return new X509Principal(c.getIssuer());
+        return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
     }
 
     public X500Principal getIssuerX500Principal()
     {
         try
         {
-            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
-
-            aOut.writeObject(c.getIssuer());
-
-            return new X500Principal(bOut.toByteArray());
+            return new X500Principal(c.getIssuer().getEncoded());
         }
         catch (IOException e)
         {
@@ -254,13 +276,21 @@
         Set entrySet = new HashSet();
         Enumeration certs = c.getRevokedCertificateEnumeration();
 
-        X500Principal previousCertificateIssuer = getIssuerX500Principal();
+        X500Name previousCertificateIssuer = null; // the issuer
         while (certs.hasMoreElements())
         {
             TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
             X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
             entrySet.add(crlEntry);
-            previousCertificateIssuer = crlEntry.getCertificateIssuer();
+            if (isIndirect && entry.hasExtensions())
+            {
+                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                if (currentCaName != null)
+                {
+                    previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                }
+            }
         }
 
         return entrySet;
@@ -270,18 +300,25 @@
     {
         Enumeration certs = c.getRevokedCertificateEnumeration();
 
-        X500Principal previousCertificateIssuer = getIssuerX500Principal();
+        X500Name previousCertificateIssuer = null; // the issuer
         while (certs.hasMoreElements())
         {
             TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
-            X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
 
             if (serialNumber.equals(entry.getUserCertificate().getValue()))
             {
-                return crlEntry;
+                return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
             }
 
-            previousCertificateIssuer = crlEntry.getCertificateIssuer();
+            if (isIndirect && entry.hasExtensions())
+            {
+                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                if (currentCaName != null)
+                {
+                    previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                }
+            }
         }
 
         return null;
@@ -324,7 +361,7 @@
 
     public String getSigAlgOID()
     {
-        return c.getSignatureAlgorithm().getObjectId().getId();
+        return c.getSignatureAlgorithm().getAlgorithm().getId();
     }
 
     public byte[] getSigAlgParams()
@@ -380,7 +417,7 @@
             }
         }
 
-        X509Extensions extensions = c.getTBSCertList().getExtensions();
+        Extensions extensions = c.getTBSCertList().getExtensions();
 
         if (extensions != null)
         {
@@ -393,25 +430,25 @@
 
             while (e.hasMoreElements())
             {
-                DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement();
-                X509Extension ext = extensions.getExtension(oid);
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+                Extension ext = extensions.getExtension(oid);
 
-                if (ext.getValue() != null)
+                if (ext.getExtnValue() != null)
                 {
-                    byte[] octs = ext.getValue().getOctets();
+                    byte[] octs = ext.getExtnValue().getOctets();
                     ASN1InputStream dIn = new ASN1InputStream(octs);
                     buf.append("                       critical(").append(
                         ext.isCritical()).append(") ");
                     try
                     {
-                        if (oid.equals(X509Extensions.CRLNumber))
+                        if (oid.equals(Extension.cRLNumber))
                         {
                             buf.append(
                                 new CRLNumber(DERInteger.getInstance(
                                     dIn.readObject()).getPositiveValue()))
                                 .append(nl);
                         }
-                        else if (oid.equals(X509Extensions.DeltaCRLIndicator))
+                        else if (oid.equals(Extension.deltaCRLIndicator))
                         {
                             buf.append(
                                 "Base CRL: "
@@ -420,24 +457,21 @@
                                 .append(nl);
                         }
                         else if (oid
-                            .equals(X509Extensions.IssuingDistributionPoint))
+                            .equals(Extension.issuingDistributionPoint))
                         {
                             buf.append(
-                                new IssuingDistributionPoint((ASN1Sequence) dIn
-                                    .readObject())).append(nl);
+                               IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
                         }
                         else if (oid
-                            .equals(X509Extensions.CRLDistributionPoints))
+                            .equals(Extension.cRLDistributionPoints))
                         {
                             buf.append(
-                                new CRLDistPoint((ASN1Sequence) dIn
-                                    .readObject())).append(nl);
+                                CRLDistPoint.getInstance(dIn.readObject())).append(nl);
                         }
-                        else if (oid.equals(X509Extensions.FreshestCRL))
+                        else if (oid.equals(Extension.freshestCRL))
                         {
                             buf.append(
-                                new CRLDistPoint((ASN1Sequence) dIn
-                                    .readObject())).append(nl);
+                                CRLDistPoint.getInstance(dIn.readObject())).append(nl);
                         }
                         else
                         {
@@ -488,14 +522,49 @@
 
         TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
 
+        X500Name caName = c.getIssuer();
+
         if (certs != null)
         {
             BigInteger serial = ((X509Certificate)cert).getSerialNumber();
 
             for (int i = 0; i < certs.length; i++)
             {
+                if (isIndirect && certs[i].hasExtensions())
+                {
+                    Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+                    if (currentCaName != null)
+                    {
+                        caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                    }
+                }
+
                 if (certs[i].getUserCertificate().getValue().equals(serial))
                 {
+                    X500Name issuer;
+
+                    if (cert instanceof  X509Certificate)
+                    {
+                        issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
+                    }
+                    else
+                    {
+                        try
+                        {
+                            issuer = org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+                        }
+                        catch (CertificateEncodingException e)
+                        {
+                            throw new RuntimeException("Cannot process certificate");
+                        }
+                    }
+
+                    if (!caName.equals(issuer))
+                    {
+                        return false;
+                    }
+
                     return true;
                 }
             }
@@ -503,28 +572,5 @@
 
         return false;
     }
-
-    private boolean isIndirectCRL()
-        throws CRLException
-    {
-        byte[] idp = getExtensionValue(X509Extensions.IssuingDistributionPoint.getId());
-        boolean isIndirect = false;
-        try
-        {
-            if (idp != null)
-            {
-                isIndirect = IssuingDistributionPoint.getInstance(
-                        X509ExtensionUtil.fromExtensionValue(idp))
-                        .isIndirectCRL();
-            }
-        }
-        catch (Exception e)
-        {
-            throw new ExtCRLException(
-                    "Exception reading IssuingDistributionPoint", e);
-        }
-
-        return isIndirect;
-    }
 }
 
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
index d52386a..e529836 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -30,12 +30,13 @@
 import javax.security.auth.x500.X500Principal;
 
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERIA5String;
 import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.DERObjectIdentifier;
@@ -44,12 +45,14 @@
 import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
 import org.bouncycastle.asn1.misc.VerisignCzagExtension;
 import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.BasicConstraints;
 import org.bouncycastle.asn1.x509.KeyUsage;
 import org.bouncycastle.asn1.x509.X509CertificateStructure;
 import org.bouncycastle.asn1.x509.X509Extension;
 import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
 import org.bouncycastle.jce.X509Principal;
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
 import org.bouncycastle.util.Arrays;
@@ -79,7 +82,7 @@
 
             if (bytes != null)
             {
-                basicConstraints = BasicConstraints.getInstance(ASN1Object.fromByteArray(bytes));
+                basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
             }
         }
         catch (Exception e)
@@ -92,7 +95,7 @@
             byte[] bytes = this.getExtensionBytes("2.5.29.15");
             if (bytes != null)
             {
-                DERBitString    bits = DERBitString.getInstance(ASN1Object.fromByteArray(bytes));
+                DERBitString    bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
 
                 bytes = bits.getBytes();
                 int length = (bytes.length * 8) - bits.getPadBits();
@@ -148,7 +151,14 @@
 
     public Principal getIssuerDN()
     {
-        return new X509Principal(c.getIssuer());
+        try
+        {
+            return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
     }
 
     public X500Principal getIssuerX500Principal()
@@ -170,7 +180,7 @@
 
     public Principal getSubjectDN()
     {
-        return new X509Principal(c.getSubject());
+        return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
     }
 
     public X500Principal getSubjectX500Principal()
@@ -205,7 +215,7 @@
     {
         try
         {
-            return c.getTBSCertificate().getEncoded(ASN1Encodable.DER);
+            return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
         }
         catch (IOException e)
         {
@@ -268,7 +278,14 @@
     {
         if (c.getSignatureAlgorithm().getParameters() != null)
         {
-            return c.getSignatureAlgorithm().getParameters().getDERObject().getDEREncoded();
+            try
+            {
+                return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                return null;
+            }
         }
         else
         {
@@ -517,7 +534,14 @@
 
     public PublicKey getPublicKey()
     {
-        return JDKKeyFactory.createPublicKeyFromPublicKeyInfo(c.getSubjectPublicKeyInfo());
+        try
+        {
+            return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+        }
+        catch (IOException e)
+        {
+            return null;   // should never happen...
+        }
     }
 
     // BEGIN android-changed
@@ -530,7 +554,7 @@
         {
             // BEGIN android-changed
             if (encoded == null) {
-                encoded = c.getEncoded(ASN1Encodable.DER);
+                encoded = c.getEncoded(ASN1Encoding.DER);
             }
             return encoded;
             // END android-changed
@@ -599,13 +623,13 @@
     }
 
     public void setBagAttribute(
-        DERObjectIdentifier oid,
-        DEREncodable        attribute)
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
     {
         attrCarrier.setBagAttribute(oid, attribute);
     }
 
-    public DEREncodable getBagAttribute(
+    public ASN1Encodable getBagAttribute(
         DERObjectIdentifier oid)
     {
         return attrCarrier.getBagAttribute(oid);
@@ -668,11 +692,11 @@
                     buf.append("                       critical(").append(ext.isCritical()).append(") ");
                     try
                     {
-                        if (oid.equals(X509Extensions.BasicConstraints))
+                        if (oid.equals(X509Extension.basicConstraints))
                         {
-                            buf.append(new BasicConstraints((ASN1Sequence)dIn.readObject())).append(nl);
+                            buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
                         }
-                        else if (oid.equals(X509Extensions.KeyUsage))
+                        else if (oid.equals(X509Extension.keyUsage))
                         {
                             buf.append(new KeyUsage((DERBitString)dIn.readObject())).append(nl);
                         }
@@ -719,7 +743,7 @@
     {
         Signature   signature;
         String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
-
+        
         try
         {
             signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
@@ -755,7 +779,7 @@
             throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
         }
 
-        DEREncodable params = c.getSignatureAlgorithm().getParameters();
+        ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
 
         // TODO This should go after the initVerify?
         X509SignatureUtil.setSignatureParameters(signature, params);
@@ -766,7 +790,7 @@
 
         if (!signature.verify(this.getSignature()))
         {
-            throw new InvalidKeyException("Public key presented not for certificate signature");
+            throw new SignatureException("certificate does not verify with supplied key");
         }
     }
 
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
index f55383e..71a4583 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -1,8 +1,17 @@
 package org.bouncycastle.jce.provider;
 
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.PSSParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Null;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
@@ -14,15 +23,6 @@
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 
-import java.io.IOException;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Signature;
-import java.security.SignatureException;
-import java.security.spec.PSSParameterSpec;
-
 class X509SignatureUtil
 {
     // BEGIN android-changed
@@ -31,7 +31,7 @@
     
     static void setSignatureParameters(
         Signature signature,
-        DEREncodable params) 
+        ASN1Encodable params)
         throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
     {
         if (params != null && !derNull.equals(params))
@@ -40,7 +40,7 @@
             
             try
             {
-                sigParams.init(params.getDERObject().getDEREncoded());
+                sigParams.init(params.toASN1Primitive().getEncoded());
             }
             catch (IOException e)
             {
@@ -64,7 +64,7 @@
     static String getSignatureName(
         AlgorithmIdentifier sigAlgId) 
     {
-        DEREncodable params = sigAlgId.getParameters();
+        ASN1Encodable params = sigAlgId.getParameters();
         
         if (params != null && !derNull.equals(params))
         {
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/EC.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/EC.java
deleted file mode 100644
index 5d873f9..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/EC.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.bouncycastle.jce.provider.asymmetric;
-
-import java.util.HashMap;
-
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
-// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
-// END android-removed
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-
-public class EC
-{
-    public static class Mappings
-        extends HashMap
-    {
-        public Mappings()
-        {
-            put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
-            // BEGIN android-removed
-            // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
-            // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
-            // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
-            // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
-            // END android-removed
-
-            put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
-            // BEGIN android-removed
-            // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
-            // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
-            // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
-            // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
-            // END android-removed
-            put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
-            // TODO Should this be an alias for ECDH?
-            put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
-            // BEGIN android-removed
-            // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-            //
-            // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
-            // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
-            // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
-            // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
-            // END android-removed
-
-            put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
-            // BEGIN android-removed
-            // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
-            // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-            // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
-            // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-            // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
-            // END android-removed
-            // TODO Should this be an alias for ECDH?
-            put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
-            // BEGIN android-removed
-            // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-            //
-            // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
-            // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
-            // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
-            // END android-removed
-
-            put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
-            put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
-
-            put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
-            put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
-            put("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
-            put("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
-            put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
-            put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
-            put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
-            // BEGIN android-removed
-            // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
-            //
-            // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-            // END android-removed
-            addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
-            addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
-            addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
-            // BEGIN android-removed
-            // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
-            //
-            // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
-            // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
-            // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
-            // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
-            // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
-            //
-            // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
-            // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
-            // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-            // END android-removed
-        }
-
-        private void addSignatureAlgorithm(
-            String digest,
-            String algorithm,
-            String className,
-            DERObjectIdentifier oid)
-        {
-            String mainName = digest + "WITH" + algorithm;
-            String jdk11Variation1 = digest + "with" + algorithm;
-            String jdk11Variation2 = digest + "With" + algorithm;
-            String alias = digest + "/" + algorithm;
-
-            put("Signature." + mainName, className);
-            put("Alg.Alias.Signature." + jdk11Variation1, mainName);
-            put("Alg.Alias.Signature." + jdk11Variation2, mainName);
-            put("Alg.Alias.Signature." + alias, mainName);
-            put("Alg.Alias.Signature." + oid, mainName);
-            put("Alg.Alias.Signature.OID." + oid, mainName);
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyFactory.java
deleted file mode 100644
index 630d2c7..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyFactory.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package org.bouncycastle.jce.provider.asymmetric.ec;
-
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-import org.bouncycastle.jce.provider.JCEECPrivateKey;
-import org.bouncycastle.jce.provider.JCEECPublicKey;
-import org.bouncycastle.jce.provider.JDKKeyFactory;
-import org.bouncycastle.jce.provider.ProviderUtil;
-import org.bouncycastle.jce.spec.ECPrivateKeySpec;
-import org.bouncycastle.jce.spec.ECPublicKeySpec;
-import org.bouncycastle.jce.spec.ECParameterSpec;
-
-public class KeyFactory
-    extends JDKKeyFactory
-{
-    String algorithm;
-
-    KeyFactory(
-        String algorithm)
-    {
-        this.algorithm = algorithm;
-    }
-
-    protected Key engineTranslateKey(
-        Key    key)
-        throws InvalidKeyException
-    {
-        if (key instanceof ECPublicKey)
-        {
-            return new JCEECPublicKey((ECPublicKey)key);
-        }
-        else if (key instanceof ECPrivateKey)
-        {
-            return new JCEECPrivateKey((ECPrivateKey)key);
-        }
-
-        throw new InvalidKeyException("key type unknown");
-    }
-
-    protected KeySpec engineGetKeySpec(
-        Key    key,
-        Class    spec)
-    throws InvalidKeySpecException
-    {
-       if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
-       {
-               return new PKCS8EncodedKeySpec(key.getEncoded());
-       }
-       else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
-       {
-               return new X509EncodedKeySpec(key.getEncoded());
-       }
-       else if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
-       {
-           ECPublicKey k = (ECPublicKey)key;
-           if (k.getParams() != null)
-           {
-               return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
-           }
-           else
-           {
-               ECParameterSpec implicitSpec = ProviderUtil.getEcImplicitlyCa();
-
-               return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
-           }
-       }
-       else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
-       {
-           ECPrivateKey k = (ECPrivateKey)key;
-
-           if (k.getParams() != null)
-           {
-               return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
-           }
-           else
-           {
-               ECParameterSpec implicitSpec = ProviderUtil.getEcImplicitlyCa();
-
-               return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); 
-           }
-       }
-
-       throw new RuntimeException("not implemented yet " + key + " " + spec);
-    }
-
-    protected PrivateKey engineGeneratePrivate(
-        KeySpec keySpec)
-        throws InvalidKeySpecException
-    {
-        if (keySpec instanceof PKCS8EncodedKeySpec)
-        {
-            try
-            {
-                JCEECPrivateKey key = (JCEECPrivateKey)JDKKeyFactory.createPrivateKeyFromDERStream(
-                    ((PKCS8EncodedKeySpec)keySpec).getEncoded());
-
-                return new JCEECPrivateKey(algorithm, key);
-            }
-            catch (Exception e)
-            {
-                throw new InvalidKeySpecException(e.toString());
-            }
-        }
-        else if (keySpec instanceof ECPrivateKeySpec)
-        {
-            return new JCEECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec);
-        }
-        else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
-        {
-            return new JCEECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec);
-        }
-
-        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
-    }
-
-    protected PublicKey engineGeneratePublic(
-        KeySpec keySpec)
-        throws InvalidKeySpecException
-    {
-        if (keySpec instanceof X509EncodedKeySpec)
-        {
-            try
-            {
-                JCEECPublicKey key = (JCEECPublicKey)JDKKeyFactory.createPublicKeyFromDERStream(
-                    ((X509EncodedKeySpec)keySpec).getEncoded());
-
-                return new JCEECPublicKey(algorithm, key);
-            }
-            catch (Exception e)
-            {
-                throw new InvalidKeySpecException(e.toString());
-            }
-        }
-        else if (keySpec instanceof ECPublicKeySpec)
-        {
-            return new JCEECPublicKey(algorithm, (ECPublicKeySpec)keySpec);
-        }
-        else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
-        {
-            return new JCEECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec);
-        }
-
-        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
-    }
-
-    public static class EC
-        extends KeyFactory
-    {
-        public EC()
-        {
-            super("EC");
-        }
-    }
-
-    public static class ECDSA
-        extends KeyFactory
-    {
-        public ECDSA()
-        {
-            super("ECDSA");
-        }
-    }
-
-    public static class ECGOST3410
-        extends KeyFactory
-    {
-        public ECGOST3410()
-        {
-            super("ECGOST3410");
-        }
-    }
-
-    public static class ECDH
-        extends KeyFactory
-    {
-        public ECDH()
-        {
-            super("ECDH");
-        }
-    }
-
-    public static class ECDHC
-        extends KeyFactory
-    {
-        public ECDHC()
-        {
-            super("ECDHC");
-        }
-    }
-
-    public static class ECMQV
-        extends KeyFactory
-    {
-        public ECMQV()
-        {
-            super("ECMQV");
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java
deleted file mode 100644
index 6076ee5..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java
+++ /dev/null
@@ -1,278 +0,0 @@
-package org.bouncycastle.jce.provider.symmetric;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.HashMap;
-
-import javax.crypto.spec.IvParameterSpec;
-
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.crypto.BufferedBlockCipher;
-import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.engines.AESFastEngine;
-import org.bouncycastle.crypto.engines.AESWrapEngine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-// import org.bouncycastle.crypto.macs.CMac;
-// END android-removed
-import org.bouncycastle.crypto.modes.CBCBlockCipher;
-import org.bouncycastle.crypto.modes.CFBBlockCipher;
-import org.bouncycastle.crypto.modes.OFBBlockCipher;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.jce.provider.JCEBlockCipher;
-import org.bouncycastle.jce.provider.JCEKeyGenerator;
-import org.bouncycastle.jce.provider.JCEMac;
-import org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator;
-import org.bouncycastle.jce.provider.JDKAlgorithmParameters;
-import org.bouncycastle.jce.provider.WrapCipherSpi;
-
-public final class AES
-{
-    private AES()
-    {
-    }
-    
-    public static class ECB
-        extends JCEBlockCipher
-    {
-        public ECB()
-        {
-            super(new AESFastEngine());
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class CBC
-    //    extends JCEBlockCipher
-    // {
-    //     public CBC()
-    //     {
-    //         super(new CBCBlockCipher(new AESFastEngine()), 128);
-    //     }
-    // }
-    //
-    // static public class CFB
-    //     extends JCEBlockCipher
-    // {
-    //     public CFB()
-    //     {
-    //         super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
-    //     }
-    // }
-    //
-    // static public class OFB
-    //     extends JCEBlockCipher
-    // {
-    //     public OFB()
-    //     {
-    //         super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
-    //     }
-    // }
-    //
-    // public static class AESCMAC
-    //     extends JCEMac
-    // {
-    //     public AESCMAC()
-    //     {
-    //         super(new CMac(new AESFastEngine()));
-    //     }
-    // }
-    // END android-removed
-
-    static public class Wrap
-        extends WrapCipherSpi
-    {
-        public Wrap()
-        {
-            super(new AESWrapEngine());
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class RFC3211Wrap
-    //     extends WrapCipherSpi
-    // {
-    //     public RFC3211Wrap()
-    //     {
-    //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
-    //     }
-    // }
-    // END android-removed
-
-    public static class KeyGen
-        extends JCEKeyGenerator
-    {
-        public KeyGen()
-        {
-            this(192);
-        }
-
-        public KeyGen(int keySize)
-        {
-            super("AES", keySize, new CipherKeyGenerator());
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class KeyGen128
-    //     extends KeyGen
-    // {
-    //     public KeyGen128()
-    //     {
-    //         super(128);
-    //     }
-    // }
-    //
-    // public static class KeyGen192
-    //     extends KeyGen
-    // {
-    //     public KeyGen192()
-    //     {
-    //         super(192);
-    //     }
-    // }
-    //
-    // public static class KeyGen256
-    //     extends KeyGen
-    // {
-    //     public KeyGen256()
-    //     {
-    //         super(256);
-    //     }
-    // }
-    //
-    // public static class AlgParamGen
-    //     extends JDKAlgorithmParameterGenerator
-    // {
-    //     protected void engineInit(
-    //         AlgorithmParameterSpec genParamSpec,
-    //         SecureRandom random)
-    //         throws InvalidAlgorithmParameterException
-    //     {
-    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
-    //     }
-    //
-    //     protected AlgorithmParameters engineGenerateParameters()
-    //     {
-    //         byte[]  iv = new byte[16];
-    //
-    //         if (random == null)
-    //         {
-    //             random = new SecureRandom();
-    //         }
-    //
-    //         random.nextBytes(iv);
-    //
-    //         AlgorithmParameters params;
-    //
-    //         try
-    //         {
-    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
-    //             params.init(new IvParameterSpec(iv));
-    //         }
-    //         catch (Exception e)
-    //         {
-    //             throw new RuntimeException(e.getMessage());
-    //         }
-    //
-    //         return params;
-    //     }
-    // }
-    // END android-removed
-
-    public static class AlgParams
-        extends JDKAlgorithmParameters.IVAlgorithmParameters
-    {
-        protected String engineToString()
-        {
-            return "AES IV";
-        }
-    }
-
-    public static class Mappings
-        extends HashMap
-    {
-        /**
-         * These three got introduced in some messages as a result of a typo in an
-         * early document. We don't produce anything using these OID values, but we'll
-         * read them.
-         */
-        private static final String wrongAES128 = "2.16.840.1.101.3.4.2";
-        private static final String wrongAES192 = "2.16.840.1.101.3.4.22";
-        private static final String wrongAES256 = "2.16.840.1.101.3.4.42";
-
-        public Mappings()
-        {
-            put("AlgorithmParameters.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParams");
-            put("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
-            put("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
-            put("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
-            put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-            put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-            put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-
-            // BEGIN android-removed
-            // put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
-            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
-            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
-            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
-            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-            // END android-removed
-
-            put("Cipher.AES", "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-            put("Alg.Alias.Cipher." + wrongAES128, "AES");
-            put("Alg.Alias.Cipher." + wrongAES192, "AES");
-            put("Alg.Alias.Cipher." + wrongAES256, "AES");
-            // BEGIN android-removed
-            // put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-            // END android-removed
-            put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$Wrap");
-            put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
-            put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
-            put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
-            // BEGIN android-removed
-            // put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
-            // END android-removed
-
-            put("KeyGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
-            // BEGIN android-removed
-            // put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-            // put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-            // put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-            // put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-            //
-            // put("Mac.AESCMAC", "org.bouncycastle.jce.provider.symmetric.AES$AESCMAC");
-            // END android-removed
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/ARC4.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/ARC4.java
deleted file mode 100644
index 1206f6c..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/symmetric/ARC4.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.bouncycastle.jce.provider.symmetric;
-
-import java.util.HashMap;
-
-import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.engines.RC4Engine;
-import org.bouncycastle.jce.provider.JCEKeyGenerator;
-import org.bouncycastle.jce.provider.JCEStreamCipher;
-
-public final class ARC4
-{
-    private ARC4()
-    {
-    }
-    
-    public static class Base
-        extends JCEStreamCipher
-    {
-        public Base()
-        {
-            super(new RC4Engine(), 0);
-        }
-    }
-
-    public static class KeyGen
-        extends JCEKeyGenerator
-    {
-        public KeyGen()
-        {
-            // BEGIN android-changed
-            super("ARC4", 128, new CipherKeyGenerator());
-            // END android-changed
-        }
-    }
-
-    public static class Mappings
-        extends HashMap
-    {
-        public Mappings()
-        {
-            put("Cipher.ARC4", "org.bouncycastle.jce.provider.symmetric.ARC4$Base");
-            put("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
-            put("Alg.Alias.Cipher.ARCFOUR", "ARC4");
-            put("Alg.Alias.Cipher.RC4", "ARC4");
-            put("KeyGenerator.ARC4", "org.bouncycastle.jce.provider.symmetric.ARC4$KeyGen");
-            put("Alg.Alias.KeyGenerator.RC4", "ARC4");
-            put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/Blowfish.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/Blowfish.java
deleted file mode 100644
index b1a8b72..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/symmetric/Blowfish.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.bouncycastle.jce.provider.symmetric;
-
-import java.util.HashMap;
-
-import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.engines.BlowfishEngine;
-import org.bouncycastle.crypto.modes.CBCBlockCipher;
-import org.bouncycastle.jce.provider.JCEBlockCipher;
-import org.bouncycastle.jce.provider.JCEKeyGenerator;
-import org.bouncycastle.jce.provider.JDKAlgorithmParameters;
-
-public final class Blowfish
-{
-    private Blowfish()
-    {
-    }
-    
-    public static class ECB
-        extends JCEBlockCipher
-    {
-        public ECB()
-        {
-            super(new BlowfishEngine());
-        }
-    }
-
-    public static class CBC
-        extends JCEBlockCipher
-    {
-        public CBC()
-        {
-            super(new CBCBlockCipher(new BlowfishEngine()), 64);
-        }
-    }
-
-    public static class KeyGen
-        extends JCEKeyGenerator
-    {
-        public KeyGen()
-        {
-            super("Blowfish", 128, new CipherKeyGenerator());
-        }
-    }
-
-    public static class AlgParams
-        extends JDKAlgorithmParameters.IVAlgorithmParameters
-    {
-        protected String engineToString()
-        {
-            return "Blowfish IV";
-        }
-    }
-
-    public static class Mappings
-        extends HashMap
-    {
-        public Mappings()
-        {
-            put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$ECB");
-            // BEGIN android-removed
-            // put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.symmetric.Blowfish$CBC");
-            // END android-removed
-            put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$KeyGen");
-            put("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
-            put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$AlgParams");
-            put("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/DESede.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/DESede.java
deleted file mode 100644
index ec35f61..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/symmetric/DESede.java
+++ /dev/null
@@ -1,313 +0,0 @@
-package org.bouncycastle.jce.provider.symmetric;
-
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.util.HashMap;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.DESedeKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.crypto.KeyGenerationParameters;
-import org.bouncycastle.crypto.engines.DESedeEngine;
-import org.bouncycastle.crypto.engines.DESedeWrapEngine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-// END android-removed
-import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
-import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
-// import org.bouncycastle.crypto.macs.CMac;
-// END android-removed
-import org.bouncycastle.crypto.modes.CBCBlockCipher;
-import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
-import org.bouncycastle.jce.provider.JCEBlockCipher;
-import org.bouncycastle.jce.provider.JCEKeyGenerator;
-import org.bouncycastle.jce.provider.JCEMac;
-import org.bouncycastle.jce.provider.JCESecretKeyFactory;
-import org.bouncycastle.jce.provider.WrapCipherSpi;
-
-public final class DESede
-{
-    private DESede()
-    {
-    }
-
-    static public class ECB
-        extends JCEBlockCipher
-    {
-        public ECB()
-        {
-            super(new DESedeEngine());
-        }
-    }
-
-    static public class CBC
-        extends JCEBlockCipher
-    {
-        public CBC()
-        {
-            super(new CBCBlockCipher(new DESedeEngine()), 64);
-        }
-    }
-
-    // BEGIN android-removed
-    // /**
-    //  * DESede   CFB8
-    //  */
-    // public static class DESedeCFB8
-    //     extends JCEMac
-    // {
-    //     public DESedeCFB8()
-    //     {
-    //         super(new CFBBlockCipherMac(new DESedeEngine()));
-    //     }
-    // }
-    // END android-removed
-
-    /**
-     * DESede64
-     */
-    public static class DESede64
-        extends JCEMac
-    {
-        public DESede64()
-        {
-            super(new CBCBlockCipherMac(new DESedeEngine(), 64));
-        }
-    }
-
-    /**
-     * DESede64with7816-4Padding
-     */
-    public static class DESede64with7816d4
-        extends JCEMac
-    {
-        public DESede64with7816d4()
-        {
-            super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
-        }
-    }
-    
-    public static class CBCMAC
-        extends JCEMac
-    {
-        public CBCMAC()
-        {
-            super(new CBCBlockCipherMac(new DESedeEngine()));
-        }
-    }
-
-    // BEGIN android-removed
-    // static public class CMAC
-    //     extends JCEMac
-    // {
-    //     public CMAC()
-    //     {
-    //         super(new CMac(new DESedeEngine()));
-    //     }
-    // }
-    // END android-removed
-
-    public static class Wrap
-        extends WrapCipherSpi
-    {
-        public Wrap()
-        {
-            super(new DESedeWrapEngine());
-        }
-    }
-
-    // BEGIN android-removed
-    // public static class RFC3211
-    //     extends WrapCipherSpi
-    // {
-    //     public RFC3211()
-    //     {
-    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
-    //     }
-    // }
-    // END android-removed
-
-  /**
-     * DESede - the default for this is to generate a key in
-     * a-b-a format that's 24 bytes long but has 16 bytes of
-     * key material (the first 8 bytes is repeated as the last
-     * 8 bytes). If you give it a size, you'll get just what you
-     * asked for.
-     */
-    public static class KeyGenerator
-        extends JCEKeyGenerator
-    {
-        private boolean     keySizeSet = false;
-
-        public KeyGenerator()
-        {
-            super("DESede", 192, new DESedeKeyGenerator());
-        }
-
-        protected void engineInit(
-            int             keySize,
-            SecureRandom random)
-        {
-            super.engineInit(keySize, random);
-            keySizeSet = true;
-        }
-
-        protected SecretKey engineGenerateKey()
-        {
-            if (uninitialised)
-            {
-                engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
-                uninitialised = false;
-            }
-
-            //
-            // if no key size has been defined generate a 24 byte key in
-            // the a-b-a format
-            //
-            if (!keySizeSet)
-            {
-                byte[]     k = engine.generateKey();
-
-                System.arraycopy(k, 0, k, 16, 8);
-
-                return new SecretKeySpec(k, algName);
-            }
-            else
-            {
-                return new SecretKeySpec(engine.generateKey(), algName);
-            }
-        }
-    }
-
-    /**
-     * generate a desEDE key in the a-b-c format.
-     */
-    public static class KeyGenerator3
-        extends JCEKeyGenerator
-    {
-        public KeyGenerator3()
-        {
-            super("DESede3", 192, new DESedeKeyGenerator());
-        }
-    }
-
-    static public class KeyFactory
-        extends JCESecretKeyFactory
-    {
-        public KeyFactory()
-        {
-            super("DESede", null);
-        }
-
-        protected KeySpec engineGetKeySpec(
-            SecretKey key,
-            Class keySpec)
-        throws InvalidKeySpecException
-        {
-            if (keySpec == null)
-            {
-                throw new InvalidKeySpecException("keySpec parameter is null");
-            }
-            if (key == null)
-            {
-                throw new InvalidKeySpecException("key parameter is null");
-            }
-
-            if (SecretKeySpec.class.isAssignableFrom(keySpec))
-            {
-                return new SecretKeySpec(key.getEncoded(), algName);
-            }
-            else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
-            {
-                byte[]  bytes = key.getEncoded();
-
-                try
-                {
-                    if (bytes.length == 16)
-                    {
-                        byte[]  longKey = new byte[24];
-
-                        System.arraycopy(bytes, 0, longKey, 0, 16);
-                        System.arraycopy(bytes, 0, longKey, 16, 8);
-
-                        return new DESedeKeySpec(longKey);
-                    }
-                    else
-                    {
-                        return new DESedeKeySpec(bytes);
-                    }
-                }
-                catch (Exception e)
-                {
-                    throw new InvalidKeySpecException(e.toString());
-                }
-            }
-
-            throw new InvalidKeySpecException("Invalid KeySpec");
-        }
-
-        protected SecretKey engineGenerateSecret(
-            KeySpec keySpec)
-        throws InvalidKeySpecException
-        {
-            if (keySpec instanceof DESedeKeySpec)
-            {
-                DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
-                return new SecretKeySpec(desKeySpec.getKey(), "DESede");
-            }
-
-            return super.engineGenerateSecret(keySpec);
-        }
-    }
-
-    public static class Mappings
-        extends HashMap
-    {
-        public Mappings()
-        {
-            put("Cipher.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$ECB");
-            // BEGIN android-removed
-            // put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
-            // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
-            // END android-removed
-            put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$Wrap");
-            // BEGIN android-changed
-            put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
-            // END android-changed
-            // BEGIN android-removed
-            // put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.DESede$RFC3211");
-            // END android-removed
-
-            put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
-            // BEGIN android-removed
-            // put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator3");
-            // put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
-            // END android-removed
-
-            put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyFactory");
-
-            // BEGIN android-removed
-            // put("Mac.DESEDECMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CMAC");
-            // put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CBCMAC");
-            // put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
-            //
-            // put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.symmetric.DESede$DESedeCFB8");
-            // put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
-            //
-            // put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64");
-            // put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
-            //
-            // put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64with7816d4");
-            // put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-            // put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-            // put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-            // END android-removed
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java b/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java
new file mode 100644
index 0000000..a5dd319
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java
@@ -0,0 +1,28 @@
+package org.bouncycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Named curve generation spec
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECGenParameterSpec.
+ */
+public class ECNamedCurveGenParameterSpec
+    implements AlgorithmParameterSpec
+{
+    private String  name;
+
+    public ECNamedCurveGenParameterSpec(
+        String name)
+    {
+        this.name = name;
+    }
+
+    /**
+     * return the name of the curve the EC domain parameters belong to.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java b/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java
new file mode 100644
index 0000000..2a7ceb5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java
@@ -0,0 +1,34 @@
+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/src/main/java/org/bouncycastle/openssl/EncryptionException.java b/src/main/java/org/bouncycastle/openssl/EncryptionException.java
deleted file mode 100644
index b839568..0000000
--- a/src/main/java/org/bouncycastle/openssl/EncryptionException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.IOException;
-
-public class EncryptionException
-    extends IOException
-{
-    private Throwable cause;
-
-    public EncryptionException(String msg)
-    {
-        super(msg);
-    }
-
-    public EncryptionException(String msg, Throwable ex)
-    {
-        super(msg);
-        this.cause = ex;
-    }
-
-    public Throwable getCause()
-    {
-        return cause;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java b/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
deleted file mode 100644
index 5793007..0000000
--- a/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
+++ /dev/null
@@ -1,335 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.Key;
-import java.security.KeyPair;
-import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
-import java.security.Provider;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.cert.CRLException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509CRL;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAParams;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.cms.ContentInfo;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
-import org.bouncycastle.asn1.x509.DSAParameter;
-import org.bouncycastle.jce.PKCS10CertificationRequest;
-import org.bouncycastle.util.Strings;
-import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.io.pem.PemGenerationException;
-import org.bouncycastle.util.io.pem.PemHeader;
-import org.bouncycastle.util.io.pem.PemObject;
-import org.bouncycastle.util.io.pem.PemObjectGenerator;
-import org.bouncycastle.x509.X509AttributeCertificate;
-import org.bouncycastle.x509.X509V2AttributeCertificate;
-
-/**
- * PEM generator for the original set of PEM objects used in Open SSL.
- */
-public class MiscPEMGenerator
-    implements PemObjectGenerator
-{
-    private Object obj;
-    private String algorithm;
-    private char[] password;
-    private SecureRandom random;
-    private Provider provider;
-
-    public MiscPEMGenerator(Object o)
-    {
-        this.obj = o;
-    }
-
-    public MiscPEMGenerator(
-        Object       obj,
-        String       algorithm,
-        char[]       password,
-        SecureRandom random,
-        Provider     provider)
-    {
-        this.obj = obj;
-        this.algorithm = algorithm;
-        this.password = password;
-        this.random = random;
-        this.provider = provider;
-    }
-
-    public MiscPEMGenerator(
-        Object       obj,
-        String       algorithm,
-        char[]       password,
-        SecureRandom random,
-        String       provider)
-        throws NoSuchProviderException
-    {
-        this.obj = obj;
-        this.algorithm = algorithm;
-        this.password = password;
-        this.random = random;
-
-        if (provider != null)
-        {
-            this.provider = Security.getProvider(provider);
-            if (this.provider == null)
-            {
-                throw new NoSuchProviderException("cannot find provider: " + provider);
-            }
-        }
-    }
-
-    private PemObject createPemObject(Object o)
-        throws IOException
-    {
-        String  type;
-        byte[]  encoding;
-
-        if (o instanceof PemObject)
-        {
-            return (PemObject)o;
-        }
-        if (o instanceof PemObjectGenerator)
-        {
-            return ((PemObjectGenerator)o).generate();
-        }
-        if (o instanceof X509Certificate)
-        {
-            type = "CERTIFICATE";
-            try
-            {
-                encoding = ((X509Certificate)o).getEncoded();
-            }
-            catch (CertificateEncodingException e)
-            {
-                throw new PemGenerationException("Cannot encode object: " + e.toString());
-            }
-        }
-        else if (o instanceof X509CRL)
-        {
-            type = "X509 CRL";
-            try
-            {
-                encoding = ((X509CRL)o).getEncoded();
-            }
-            catch (CRLException e)
-            {
-                throw new PemGenerationException("Cannot encode object: " + e.toString());
-            }
-        }
-        else if (o instanceof KeyPair)
-        {
-            return createPemObject(((KeyPair)o).getPrivate());
-        }
-        else if (o instanceof PrivateKey)
-        {
-            PrivateKeyInfo info = new PrivateKeyInfo(
-                (ASN1Sequence) ASN1Object.fromByteArray(((Key)o).getEncoded()));
-
-            if (o instanceof RSAPrivateKey)
-            {
-                type = "RSA PRIVATE KEY";
-
-                encoding = info.getPrivateKey().getEncoded();
-            }
-            else if (o instanceof DSAPrivateKey)
-            {
-                type = "DSA PRIVATE KEY";
-
-                DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
-                ASN1EncodableVector v = new ASN1EncodableVector();
-
-                v.add(new DERInteger(0));
-                v.add(new DERInteger(p.getP()));
-                v.add(new DERInteger(p.getQ()));
-                v.add(new DERInteger(p.getG()));
-
-                BigInteger x = ((DSAPrivateKey)o).getX();
-                BigInteger y = p.getG().modPow(x, p.getP());
-
-                v.add(new DERInteger(y));
-                v.add(new DERInteger(x));
-
-                encoding = new DERSequence(v).getEncoded();
-            }
-            else if (((PrivateKey)o).getAlgorithm().equals("ECDSA"))
-            {
-                type = "EC PRIVATE KEY";
-
-                encoding = info.getPrivateKey().getEncoded();
-            }
-            else
-            {
-                throw new IOException("Cannot identify private key");
-            }
-        }
-        else if (o instanceof PublicKey)
-        {
-            type = "PUBLIC KEY";
-
-            encoding = ((PublicKey)o).getEncoded();
-        }
-        else if (o instanceof X509AttributeCertificate)
-        {
-            type = "ATTRIBUTE CERTIFICATE";
-            encoding = ((X509V2AttributeCertificate)o).getEncoded();
-        }
-        else if (o instanceof PKCS10CertificationRequest)
-        {
-            type = "CERTIFICATE REQUEST";
-            encoding = ((PKCS10CertificationRequest)o).getEncoded();
-        }
-        else if (o instanceof ContentInfo)
-        {
-            type = "PKCS7";
-            encoding = ((ContentInfo)o).getEncoded();
-        }
-        else
-        {
-            throw new PemGenerationException("unknown object passed - can't encode.");
-        }
-
-        return new PemObject(type, encoding);
-    }
-
-    private String getHexEncoded(byte[] bytes)
-        throws IOException
-    {
-        bytes = Hex.encode(bytes);
-
-        char[] chars = new char[bytes.length];
-
-        for (int i = 0; i != bytes.length; i++)
-        {
-            chars[i] = (char)bytes[i];
-        }
-
-        return new String(chars);
-    }
-
-    private PemObject createPemObject(
-        Object       obj,
-        String       algorithm,
-        char[]       password,
-        SecureRandom random)
-        throws IOException
-    {
-        if (obj instanceof KeyPair)
-        {
-            return createPemObject(((KeyPair)obj).getPrivate(), algorithm, password, random);
-        }
-
-        String type = null;
-        byte[] keyData = null;
-
-        if (obj instanceof RSAPrivateCrtKey)
-        {
-            type = "RSA PRIVATE KEY";
-
-            RSAPrivateCrtKey k = (RSAPrivateCrtKey)obj;
-
-            RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
-                k.getModulus(),
-                k.getPublicExponent(),
-                k.getPrivateExponent(),
-                k.getPrimeP(),
-                k.getPrimeQ(),
-                k.getPrimeExponentP(),
-                k.getPrimeExponentQ(),
-                k.getCrtCoefficient());
-
-            // convert to bytearray
-            keyData = keyStruct.getEncoded();
-        }
-        else if (obj instanceof DSAPrivateKey)
-        {
-            type = "DSA PRIVATE KEY";
-
-            DSAPrivateKey       k = (DSAPrivateKey)obj;
-            DSAParams p = k.getParams();
-            ASN1EncodableVector v = new ASN1EncodableVector();
-
-            v.add(new DERInteger(0));
-            v.add(new DERInteger(p.getP()));
-            v.add(new DERInteger(p.getQ()));
-            v.add(new DERInteger(p.getG()));
-
-            BigInteger x = k.getX();
-            BigInteger y = p.getG().modPow(x, p.getP());
-
-            v.add(new DERInteger(y));
-            v.add(new DERInteger(x));
-
-            keyData = new DERSequence(v).getEncoded();
-        }
-        else if (obj instanceof PrivateKey && "ECDSA".equals(((PrivateKey)obj).getAlgorithm()))
-        {
-            type = "EC PRIVATE KEY";
-
-            PrivateKeyInfo      privInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(((PrivateKey)obj).getEncoded()));
-
-            keyData = privInfo.getPrivateKey().getEncoded();
-        }
-
-        if (type == null || keyData == null)
-        {
-            // TODO Support other types?
-            throw new IllegalArgumentException("Object type not supported: " + obj.getClass().getName());
-        }
-
-        String dekAlgName = Strings.toUpperCase(algorithm);
-
-        // Note: For backward compatibility
-        if (dekAlgName.equals("DESEDE"))
-        {
-            dekAlgName = "DES-EDE3-CBC";
-        }
-
-        int ivLength = dekAlgName.startsWith("AES-") ? 16 : 8;
-
-        byte[] iv = new byte[ivLength];
-        random.nextBytes(iv);
-
-        byte[] encData = PEMUtilities.crypt(true, provider, keyData, password, dekAlgName, iv);
-
-        List headers = new ArrayList(2);
-
-        headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
-        headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv)));
-
-        return new PemObject(type, headers, encData);
-    }
-
-    public PemObject generate()
-        throws PemGenerationException
-    {
-        try
-        {
-            if (algorithm != null)
-            {
-                return createPemObject(obj, algorithm, password, random);
-            }
-
-            return createPemObject(obj);
-        }
-        catch (IOException e)
-        {
-            throw new PemGenerationException("encoding exception: " + e.getMessage(), e);
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMException.java b/src/main/java/org/bouncycastle/openssl/PEMException.java
deleted file mode 100644
index 3753aec..0000000
--- a/src/main/java/org/bouncycastle/openssl/PEMException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.IOException;
-
-public class PEMException
-    extends IOException
-{
-    Exception    underlying;
-
-    public PEMException(
-        String    message)
-    {
-        super(message);
-    }
-
-    public PEMException(
-        String        message,
-        Exception    underlying)
-    {
-        super(message);
-        this.underlying = underlying;
-    }
-
-    public Exception getUnderlyingException()
-    {
-        return underlying;
-    }
-
-
-    public Throwable getCause()
-    {
-        return underlying;
-    }
-}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMReader.java b/src/main/java/org/bouncycastle/openssl/PEMReader.java
deleted file mode 100644
index 92bf8f9..0000000
--- a/src/main/java/org/bouncycastle/openssl/PEMReader.java
+++ /dev/null
@@ -1,804 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.Reader;
-import java.security.AlgorithmParameters;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PublicKey;
-import java.security.cert.CertificateFactory;
-import java.security.spec.DSAPrivateKeySpec;
-import java.security.spec.DSAPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.PBEParameterSpec;
-
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cms.ContentInfo;
-import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.EncryptionScheme;
-import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
-import org.bouncycastle.asn1.pkcs.PBEParameter;
-import org.bouncycastle.asn1.pkcs.PBES2Parameters;
-import org.bouncycastle.asn1.pkcs.PBKDF2Params;
-import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.jce.ECNamedCurveTable;
-import org.bouncycastle.jce.PKCS10CertificationRequest;
-import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.io.pem.PemHeader;
-import org.bouncycastle.util.io.pem.PemObject;
-import org.bouncycastle.util.io.pem.PemObjectParser;
-import org.bouncycastle.util.io.pem.PemReader;
-import org.bouncycastle.x509.X509V2AttributeCertificate;
-
-/**
- * Class for reading OpenSSL PEM encoded streams containing
- * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
- * <p>
- * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
- * Certificates will be returned using the appropriate java.security type (KeyPair, PublicKey, X509Certificate,
- * or X509CRL). In the case of a Certificate Request a PKCS10CertificationRequest will be returned.
- * </p>
- */
-public class PEMReader
-    extends PemReader
-{
-    private final Map parsers = new HashMap();
-
-    private PasswordFinder pFinder;
-
-
-    /**
-     * Create a new PEMReader
-     *
-     * @param reader the Reader
-     */
-    public PEMReader(
-        Reader reader)
-    {
-        this(reader, null, "BC");
-    }
-
-    /**
-     * Create a new PEMReader with a password finder
-     *
-     * @param reader  the Reader
-     * @param pFinder the password finder
-     */
-    public PEMReader(
-        Reader reader,
-        PasswordFinder pFinder)
-    {
-        this(reader, pFinder, "BC");
-    }
-
-    /**
-     * Create a new PEMReader with a password finder
-     *
-     * @param reader   the Reader
-     * @param pFinder  the password finder
-     * @param provider the cryptography provider to use
-     */
-    public PEMReader(
-        Reader reader,
-        PasswordFinder pFinder,
-        String provider)
-    {
-        this(reader, pFinder, provider, provider);
-    }
-
-    /**
-     * Create a new PEMReader with a password finder and differing providers for secret and public key
-     * operations.
-     *
-     * @param reader   the Reader
-     * @param pFinder  the password finder
-     * @param symProvider  provider to use for symmetric operations
-     * @param asymProvider provider to use for asymmetric (public/private key) operations
-     */
-    public PEMReader(
-        Reader reader,
-        PasswordFinder pFinder,
-        String symProvider,
-        String asymProvider)
-    {
-        super(reader);
-
-        this.pFinder = pFinder;
-
-        parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
-        parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
-        parsers.put("CERTIFICATE", new X509CertificateParser(asymProvider));
-        parsers.put("X509 CERTIFICATE", new X509CertificateParser(asymProvider));
-        parsers.put("X509 CRL", new X509CRLParser(asymProvider));
-        parsers.put("PKCS7", new PKCS7Parser());
-        parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser());
-        parsers.put("EC PARAMETERS", new ECNamedCurveSpecParser());
-        parsers.put("PUBLIC KEY", new PublicKeyParser(asymProvider));
-        parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser(asymProvider));
-        parsers.put("RSA PRIVATE KEY", new RSAKeyPairParser(asymProvider));
-        parsers.put("DSA PRIVATE KEY", new DSAKeyPairParser(asymProvider));
-        parsers.put("EC PRIVATE KEY", new ECDSAKeyPairParser(asymProvider));
-        parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(symProvider, asymProvider));
-        parsers.put("PRIVATE KEY", new PrivateKeyParser(asymProvider));
-    }
-
-    public Object readObject()
-        throws IOException
-    {
-        PemObject obj = readPemObject();
-
-        if (obj != null)
-        {
-            String type = obj.getType();
-            if (parsers.containsKey(type))
-            {
-                return ((PemObjectParser)parsers.get(type)).parseObject(obj);
-            }
-            else
-            {
-                throw new IOException("unrecognised object: " + type);
-            }
-        }
-
-        return null;
-    }
-
-    private abstract class KeyPairParser
-        implements PemObjectParser
-    {
-        protected String provider;
-
-        public KeyPairParser(String provider)
-        {
-            this.provider = provider;
-        }
-
-        /**
-         * Read a Key Pair
-         */
-        protected ASN1Sequence readKeyPair(
-            PemObject obj)
-            throws IOException
-        {
-            boolean isEncrypted = false;
-            String dekInfo = null;
-            List headers = obj.getHeaders();
-
-            for (Iterator it = headers.iterator(); it.hasNext();)
-            {
-                PemHeader hdr = (PemHeader)it.next();
-
-                if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED"))
-                {
-                    isEncrypted = true;
-                }
-                else if (hdr.getName().equals("DEK-Info"))
-                {
-                    dekInfo = hdr.getValue();
-                }
-            }
-
-            //
-            // extract the key
-            //
-            byte[] keyBytes = obj.getContent();
-
-            if (isEncrypted)
-            {
-                if (pFinder == null)
-                {
-                    throw new PasswordException("No password finder specified, but a password is required");
-                }
-
-                char[] password = pFinder.getPassword();
-
-                if (password == null)
-                {
-                    throw new PasswordException("Password is null, but a password is required");
-                }
-
-                StringTokenizer tknz = new StringTokenizer(dekInfo, ",");
-                String dekAlgName = tknz.nextToken();
-                byte[] iv = Hex.decode(tknz.nextToken());
-
-                keyBytes = PEMUtilities.crypt(false, provider, keyBytes, password, dekAlgName, iv);
-            }
-
-            try
-            {
-                return (ASN1Sequence)ASN1Object.fromByteArray(keyBytes);
-            }
-            catch (IOException e)
-            {
-                if (isEncrypted)
-                {
-                    throw new PEMException("exception decoding - please check password and data.", e);
-                }
-                else
-                {
-                    throw new PEMException(e.getMessage(), e);
-                }
-            }
-            catch (ClassCastException e)
-            {
-                if (isEncrypted)
-                {
-                    throw new PEMException("exception decoding - please check password and data.", e);
-                }
-                else
-                {
-                    throw new PEMException(e.getMessage(), e);
-                }
-            }
-        }
-    }
-
-    private class DSAKeyPairParser
-        extends KeyPairParser
-    {
-        public DSAKeyPairParser(String provider)
-        {
-            super(provider);
-        }
-
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                ASN1Sequence seq = readKeyPair(obj);
-
-                if (seq.size() != 6)
-                {
-                    throw new PEMException("malformed sequence in DSA private key");
-                }
-
-                //            DERInteger              v = (DERInteger)seq.getObjectAt(0);
-                DERInteger p = (DERInteger)seq.getObjectAt(1);
-                DERInteger q = (DERInteger)seq.getObjectAt(2);
-                DERInteger g = (DERInteger)seq.getObjectAt(3);
-                DERInteger y = (DERInteger)seq.getObjectAt(4);
-                DERInteger x = (DERInteger)seq.getObjectAt(5);
-
-                DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec(
-                    x.getValue(), p.getValue(),
-                    q.getValue(), g.getValue());
-                DSAPublicKeySpec pubSpec = new DSAPublicKeySpec(
-                    y.getValue(), p.getValue(),
-                    q.getValue(), g.getValue());
-
-                KeyFactory fact = KeyFactory.getInstance("DSA", provider);
-
-                return new KeyPair(
-                    fact.generatePublic(pubSpec),
-                    fact.generatePrivate(privSpec));
-            }
-            catch (IOException e)
-            {
-                throw e;
-            }
-            catch (Exception e)
-            {
-                throw new PEMException(
-                    "problem creating DSA private key: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class ECDSAKeyPairParser
-        extends KeyPairParser
-    {
-        public ECDSAKeyPairParser(String provider)
-        {
-            super(provider);
-        }
-
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                ASN1Sequence seq = readKeyPair(obj);
-
-                ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq);
-                AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters());
-                PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.getDERObject());
-                SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes());
-
-                PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded());
-                X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
-
-
-                KeyFactory fact = KeyFactory.getInstance("ECDSA", provider);
-
-
-                return new KeyPair(
-                    fact.generatePublic(pubSpec),
-                    fact.generatePrivate(privSpec));
-            }
-            catch (IOException e)
-            {
-                throw e;
-            }
-            catch (Exception e)
-            {
-                throw new PEMException(
-                    "problem creating EC private key: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class RSAKeyPairParser
-        extends KeyPairParser
-    {
-        public RSAKeyPairParser(String provider)
-        {
-            super(provider);
-        }
-
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                ASN1Sequence seq = readKeyPair(obj);
-
-                if (seq.size() != 9)
-                {
-                    throw new PEMException("malformed sequence in RSA private key");
-                }
-
-                //            DERInteger              v = (DERInteger)seq.getObjectAt(0);
-                DERInteger mod = (DERInteger)seq.getObjectAt(1);
-                DERInteger pubExp = (DERInteger)seq.getObjectAt(2);
-                DERInteger privExp = (DERInteger)seq.getObjectAt(3);
-                DERInteger p1 = (DERInteger)seq.getObjectAt(4);
-                DERInteger p2 = (DERInteger)seq.getObjectAt(5);
-                DERInteger exp1 = (DERInteger)seq.getObjectAt(6);
-                DERInteger exp2 = (DERInteger)seq.getObjectAt(7);
-                DERInteger crtCoef = (DERInteger)seq.getObjectAt(8);
-
-                RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(
-                    mod.getValue(), pubExp.getValue());
-                RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec(
-                    mod.getValue(), pubExp.getValue(), privExp.getValue(),
-                    p1.getValue(), p2.getValue(),
-                    exp1.getValue(), exp2.getValue(),
-                    crtCoef.getValue());
-
-
-                KeyFactory fact = KeyFactory.getInstance("RSA", provider);
-
-
-                return new KeyPair(
-                    fact.generatePublic(pubSpec),
-                    fact.generatePrivate(privSpec));
-            }
-            catch (IOException e)
-            {
-                throw e;
-            }
-            catch (Exception e)
-            {
-                throw new PEMException(
-                    "problem creating RSA private key: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class PublicKeyParser
-        implements PemObjectParser
-    {
-        private String provider;
-
-        public PublicKeyParser(String provider)
-        {
-            this.provider = provider;
-        }
-
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            KeySpec keySpec = new X509EncodedKeySpec(obj.getContent());
-            String[] algorithms = {"DSA", "RSA"};
-            for (int i = 0; i < algorithms.length; i++)
-            {
-                try
-                {
-                    KeyFactory keyFact = KeyFactory.getInstance(algorithms[i], provider);
-                    PublicKey pubKey = keyFact.generatePublic(keySpec);
-
-                    return pubKey;
-                }
-                catch (NoSuchAlgorithmException e)
-                {
-                    // ignore
-                }
-                catch (InvalidKeySpecException e)
-                {
-                    // ignore
-                }
-                catch (NoSuchProviderException e)
-                {
-                    throw new RuntimeException("can't find provider " + provider);
-                }
-            }
-
-            return null;
-        }
-    }
-
-    private class RSAPublicKeyParser
-        implements PemObjectParser
-    {
-        private String provider;
-
-        public RSAPublicKeyParser(String provider)
-        {
-            this.provider = provider;
-        }
-
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                ASN1InputStream ais = new ASN1InputStream(obj.getContent());
-                Object asnObject = ais.readObject();
-                ASN1Sequence sequence = (ASN1Sequence)asnObject;
-                RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence);
-                RSAPublicKeySpec keySpec = new RSAPublicKeySpec(
-                    rsaPubStructure.getModulus(),
-                    rsaPubStructure.getPublicExponent());
-
-
-                    KeyFactory keyFact = KeyFactory.getInstance("RSA", provider);
-
-                    return keyFact.generatePublic(keySpec);
-            }
-            catch (IOException e)
-            {
-                throw e;
-            }
-            catch (NoSuchProviderException e)
-            {
-                throw new IOException("can't find provider " + provider);
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem extracting key: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class X509CertificateParser
-        implements PemObjectParser
-    {
-        private String provider;
-
-        public X509CertificateParser(String provider)
-        {
-            this.provider = provider;
-        }
-
-        /**
-         * Reads in a X509Certificate.
-         *
-         * @return the X509Certificate
-         * @throws IOException if an I/O error occured
-         */
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent());
-
-            try
-            {
-                CertificateFactory certFact
-                    = CertificateFactory.getInstance("X.509", provider);
-
-                return certFact.generateCertificate(bIn);
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem parsing cert: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class X509CRLParser
-        implements PemObjectParser
-    {
-        private String provider;
-
-        public X509CRLParser(String provider)
-        {
-            this.provider = provider;
-        }
-
-        /**
-         * Reads in a X509CRL.
-         *
-         * @return the X509Certificate
-         * @throws IOException if an I/O error occured
-         */
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent());
-
-            try
-            {
-                CertificateFactory certFact
-                    = CertificateFactory.getInstance("X.509", provider);
-
-                return certFact.generateCRL(bIn);
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem parsing cert: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class PKCS10CertificationRequestParser
-        implements PemObjectParser
-    {
-        /**
-         * Reads in a PKCS10 certification request.
-         *
-         * @return the certificate request.
-         * @throws IOException if an I/O error occured
-         */
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                return new PKCS10CertificationRequest(obj.getContent());
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem parsing certrequest: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class PKCS7Parser
-        implements PemObjectParser
-    {
-        /**
-         * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
-         * API.
-         *
-         * @return the X509Certificate
-         * @throws IOException if an I/O error occured
-         */
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                ASN1InputStream aIn = new ASN1InputStream(obj.getContent());
-
-                return ContentInfo.getInstance(aIn.readObject());
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class X509AttributeCertificateParser
-        implements PemObjectParser
-    {
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            return new X509V2AttributeCertificate(obj.getContent());
-        }
-    }
-
-    private class ECNamedCurveSpecParser
-        implements PemObjectParser
-    {
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                DERObjectIdentifier oid = (DERObjectIdentifier)ASN1Object.fromByteArray(obj.getContent());
-
-                Object params = ECNamedCurveTable.getParameterSpec(oid.getId());
-
-                if (params == null)
-                {
-                    throw new IOException("object ID not found in EC curve table");
-                }
-
-                return params;
-            }
-            catch (IOException e)
-            {
-                throw e;
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("exception extracting EC named curve: " + e.toString());
-            }
-        }
-    }
-
-    private class EncryptedPrivateKeyParser
-        implements PemObjectParser
-    {
-        private String symProvider;
-        private String asymProvider;
-
-        public EncryptedPrivateKeyParser(String symProvider, String asymProvider)
-        {
-            this.symProvider = symProvider;
-            this.asymProvider = asymProvider;
-        }
-
-        /**
-         * Reads in a X509CRL.
-         *
-         * @return the X509Certificate
-         * @throws IOException if an I/O error occured
-         */
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                EncryptedPrivateKeyInfo info = EncryptedPrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent()));
-                AlgorithmIdentifier algId = info.getEncryptionAlgorithm();
-
-                if (pFinder == null)
-                {
-                    throw new PEMException("no PasswordFinder specified");
-                }
-
-                if (PEMUtilities.isPKCS5Scheme2(algId.getAlgorithm()))
-                {
-                    PBES2Parameters params = PBES2Parameters.getInstance(algId.getParameters());
-                    KeyDerivationFunc func = params.getKeyDerivationFunc();
-                    EncryptionScheme scheme = params.getEncryptionScheme();
-                    PBKDF2Params defParams = (PBKDF2Params)func.getParameters();
-
-                    int iterationCount = defParams.getIterationCount().intValue();
-                    byte[] salt = defParams.getSalt();
-
-                    String algorithm = scheme.getAlgorithm().getId();
-
-                    SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algorithm, pFinder.getPassword(), salt, iterationCount);
-
-                    Cipher cipher = Cipher.getInstance(algorithm, symProvider);
-                    AlgorithmParameters algParams = AlgorithmParameters.getInstance(algorithm, symProvider);
-
-                    algParams.init(scheme.getParameters().getDERObject().getEncoded());
-
-                    cipher.init(Cipher.DECRYPT_MODE, key, algParams);
-
-                    PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
-                    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
-
-                    KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
-
-                    return keyFact.generatePrivate(keySpec);
-                }
-                else if (PEMUtilities.isPKCS12(algId.getAlgorithm()))
-                {
-                    PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters());
-                    String algorithm = algId.getAlgorithm().getId();
-                    PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword());
-
-                    SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider);
-                    PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue());
-
-                    Cipher cipher = Cipher.getInstance(algorithm, symProvider);
-
-                    cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
-
-                    PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
-                    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
-
-                    KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
-
-                    return keyFact.generatePrivate(keySpec);
-                }
-                else if (PEMUtilities.isPKCS5Scheme1(algId.getAlgorithm()))
-                {
-                    PBEParameter params = PBEParameter.getInstance(algId.getParameters());
-                    String algorithm = algId.getAlgorithm().getId();
-                    PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword());
-
-                    SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider);
-                    PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue());
-
-                    Cipher cipher = Cipher.getInstance(algorithm, symProvider);
-
-                    cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
-
-                    PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
-                    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
-
-                    KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
-
-                    return keyFact.generatePrivate(keySpec);
-                }
-                else
-                {
-                    throw new PEMException("Unknown algorithm: " + algId.getAlgorithm());
-                }
-            }
-            catch (IOException e)
-            {
-                throw e;
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e);
-            }
-        }
-    }
-
-    private class PrivateKeyParser
-        implements PemObjectParser
-    {
-        private String provider;
-
-        public PrivateKeyParser(String provider)
-        {
-            this.provider = provider;
-        }
-
-        public Object parseObject(PemObject obj)
-            throws IOException
-        {
-            try
-            {
-                PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent()));
-                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(obj.getContent());
-
-                KeyFactory keyFact = KeyFactory.getInstance(info.getAlgorithmId().getAlgorithm().getId(), provider);
-
-                return keyFact.generatePrivate(keySpec);
-            }
-            catch (Exception e)
-            {
-                throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e);
-            }
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMUtilities.java b/src/main/java/org/bouncycastle/openssl/PEMUtilities.java
deleted file mode 100644
index c955e4d..0000000
--- a/src/main/java/org/bouncycastle/openssl/PEMUtilities.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.IOException;
-import java.security.Key;
-import java.security.Provider;
-import java.security.Security;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.RC2ParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.crypto.PBEParametersGenerator;
-import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
-import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
-import org.bouncycastle.crypto.params.KeyParameter;
-
-final class PEMUtilities
-{
-    private static final Map KEYSIZES = new HashMap();
-    private static final Set PKCS5_SCHEME_1 = new HashSet();
-    private static final Set PKCS5_SCHEME_2 = new HashSet();
-
-    static
-    {
-        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC);
-        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC);
-        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC);
-        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC);
-        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC);
-        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC);
-
-        PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2);
-        PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC);
-        PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC);
-        PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
-        PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
-
-        // BEGIN android-changed
-        KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integer.valueOf(192));
-        KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integer.valueOf(128));
-        KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integer.valueOf(192));
-        KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integer.valueOf(256));
-        // END android-changed
-    }
-
-    static int getKeySize(String algorithm)
-    {
-        if (!KEYSIZES.containsKey(algorithm))
-        {
-            throw new IllegalStateException("no key size for algorithm: " + algorithm);
-        }
-        
-        return ((Integer)KEYSIZES.get(algorithm)).intValue();
-    }
-
-    static boolean isPKCS5Scheme1(DERObjectIdentifier algOid)
-    {
-        return PKCS5_SCHEME_1.contains(algOid);
-    }
-
-    static boolean isPKCS5Scheme2(DERObjectIdentifier algOid)
-    {
-        return PKCS5_SCHEME_2.contains(algOid);
-    }
-
-    static boolean isPKCS12(DERObjectIdentifier algOid)
-    {
-        return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId());
-    }
-
-    static SecretKey generateSecretKeyForPKCS5Scheme2(String algorithm, char[] password, byte[] salt, int iterationCount)
-    {
-        PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
-
-        generator.init(
-            PBEParametersGenerator.PKCS5PasswordToBytes(password),
-            salt,
-            iterationCount);
-
-        return new SecretKeySpec(((KeyParameter)generator.generateDerivedParameters(PEMUtilities.getKeySize(algorithm))).getKey(), algorithm);
-    }
-
-    static byte[] crypt(
-        boolean encrypt,
-        String provider,
-        byte[]  bytes,
-        char[]  password,
-        String  dekAlgName,
-        byte[]  iv)
-        throws IOException
-    {
-        Provider prov = null;
-        if (provider != null)
-        {
-            prov = Security.getProvider(provider);
-            if (prov == null)
-            {
-                throw new EncryptionException("cannot find provider: " + provider);
-            }
-        }
-
-        return crypt(encrypt, prov, bytes, password, dekAlgName, iv);
-    }
-
-    static byte[] crypt(
-        boolean encrypt,
-        Provider provider,
-        byte[]  bytes,
-        char[]  password,
-        String  dekAlgName,
-        byte[]  iv)
-        throws IOException
-    {
-        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
-        String                 alg;
-        String                 blockMode = "CBC";
-        String                 padding = "PKCS5Padding";
-        Key                    sKey;
-
-        // Figure out block mode and padding.
-        if (dekAlgName.endsWith("-CFB"))
-        {
-            blockMode = "CFB";
-            padding = "NoPadding";
-        }
-        if (dekAlgName.endsWith("-ECB") ||
-            "DES-EDE".equals(dekAlgName) ||
-            "DES-EDE3".equals(dekAlgName))
-        {
-            // ECB is actually the default (though seldom used) when OpenSSL
-            // uses DES-EDE (des2) or DES-EDE3 (des3).
-            blockMode = "ECB";
-            paramSpec = null;
-        }
-        if (dekAlgName.endsWith("-OFB"))
-        {
-            blockMode = "OFB";
-            padding = "NoPadding";
-        }
-
-
-        // Figure out algorithm and key size.
-        if (dekAlgName.startsWith("DES-EDE"))
-        {
-            alg = "DESede";
-            // "DES-EDE" is actually des2 in OpenSSL-speak!
-            // "DES-EDE3" is des3.
-            boolean des2 = !dekAlgName.startsWith("DES-EDE3");
-            sKey = getKey(password, alg, 24, iv, des2);
-        }
-        else if (dekAlgName.startsWith("DES-"))
-        {
-            alg = "DES";
-            sKey = getKey(password, alg, 8, iv);
-        }
-        else if (dekAlgName.startsWith("BF-"))
-        {
-            alg = "Blowfish";
-            sKey = getKey(password, alg, 16, iv);
-        }
-        else if (dekAlgName.startsWith("RC2-"))
-        {
-            alg = "RC2";
-            int keyBits = 128;
-            if (dekAlgName.startsWith("RC2-40-"))
-            {
-                keyBits = 40;
-            }
-            else if (dekAlgName.startsWith("RC2-64-"))
-            {
-                keyBits = 64;
-            }
-            sKey = getKey(password, alg, keyBits / 8, iv);
-            if (paramSpec == null) // ECB block mode
-            {
-                paramSpec = new RC2ParameterSpec(keyBits);
-            }
-            else
-            {
-                paramSpec = new RC2ParameterSpec(keyBits, iv);
-            }
-        }
-        else if (dekAlgName.startsWith("AES-"))
-        {
-            alg = "AES";
-            byte[] salt = iv;
-            if (salt.length > 8)
-            {
-                salt = new byte[8];
-                System.arraycopy(iv, 0, salt, 0, 8);
-            }
-
-            int keyBits;
-            if (dekAlgName.startsWith("AES-128-"))
-            {
-                keyBits = 128;
-            }
-            else if (dekAlgName.startsWith("AES-192-"))
-            {
-                keyBits = 192;
-            }
-            else if (dekAlgName.startsWith("AES-256-"))
-            {
-                keyBits = 256;
-            }
-            else
-            {
-                throw new EncryptionException("unknown AES encryption with private key");
-            }
-            sKey = getKey(password, "AES", keyBits / 8, salt);
-        }
-        else
-        {
-            throw new EncryptionException("unknown encryption with private key");
-        }
-
-        String transformation = alg + "/" + blockMode + "/" + padding;
-
-        try
-        {
-            Cipher c = Cipher.getInstance(transformation, provider);
-            int    mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
-
-            if (paramSpec == null) // ECB block mode
-            {
-                c.init(mode, sKey);
-            }
-            else
-            {
-                c.init(mode, sKey, paramSpec);
-            }
-            return c.doFinal(bytes);
-        }
-        catch (Exception e)
-        {
-            throw new EncryptionException("exception using cipher - please check password and data.", e);
-        }
-    }
-
-    private static SecretKey getKey(
-        char[]  password,
-        String  algorithm,
-        int     keyLength,
-        byte[]  salt)
-    {
-        return getKey(password, algorithm, keyLength, salt, false);
-    }
-
-    private static SecretKey getKey(
-        char[]  password,
-        String  algorithm,
-        int     keyLength,
-        byte[]  salt,
-        boolean des2)
-    {
-        OpenSSLPBEParametersGenerator   pGen = new OpenSSLPBEParametersGenerator();
-
-        pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
-
-        KeyParameter keyParam;
-        keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8);
-        byte[] key = keyParam.getKey();
-        if (des2 && key.length >= 24)
-        {
-            // For DES2, we must copy first 8 bytes into the last 8 bytes.
-            System.arraycopy(key, 0, key, 16, 8);
-        }
-        return new javax.crypto.spec.SecretKeySpec(key, algorithm);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMWriter.java b/src/main/java/org/bouncycastle/openssl/PEMWriter.java
deleted file mode 100644
index 834252f..0000000
--- a/src/main/java/org/bouncycastle/openssl/PEMWriter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.security.NoSuchProviderException;
-import java.security.SecureRandom;
-
-import org.bouncycastle.util.io.pem.PemGenerationException;
-import org.bouncycastle.util.io.pem.PemObjectGenerator;
-import org.bouncycastle.util.io.pem.PemWriter;
-
-/**
- * General purpose writer for OpenSSL PEM objects.
- */
-public class PEMWriter
-    extends PemWriter
-{
-    private String provider;
-
-    /**
-     * Base constructor.
-     * 
-     * @param out output stream to use.
-     */
-    public PEMWriter(Writer out)
-    {
-        this(out, "BC");
-    }
-
-    public PEMWriter(
-        Writer  out,
-        String  provider)
-    {
-        super(out);
-
-        this.provider = provider;
-    }
-
-    public void writeObject(
-        Object  obj)
-        throws IOException
-    {
-        try
-        {
-            super.writeObject(new MiscPEMGenerator(obj));
-        }
-        catch (PemGenerationException e)
-        {
-            if (e.getCause() instanceof IOException)
-            {
-                throw (IOException)e.getCause();
-            }
-
-            throw e;
-        }
-    }
-
-    public void writeObject(
-        PemObjectGenerator obj)
-        throws IOException
-    {
-        super.writeObject(obj);
-    }
-
-    public void writeObject(
-        Object       obj,
-        String       algorithm,
-        char[]       password,
-        SecureRandom random)
-        throws IOException
-    {
-        try
-        {
-            super.writeObject(new MiscPEMGenerator(obj, algorithm, password, random, provider));
-        }
-        catch (NoSuchProviderException e)
-        {
-            throw new EncryptionException(e.getMessage(), e);
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/openssl/PasswordException.java b/src/main/java/org/bouncycastle/openssl/PasswordException.java
deleted file mode 100644
index c2b8ccd..0000000
--- a/src/main/java/org/bouncycastle/openssl/PasswordException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.bouncycastle.openssl;
-
-import java.io.IOException;
-
-public class PasswordException
-    extends IOException
-{
-    public PasswordException(String msg)
-    {
-        super(msg);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/openssl/PasswordFinder.java b/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
deleted file mode 100644
index fb89cf0..0000000
--- a/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.bouncycastle.openssl;
-
-/**
- * call back to allow a password to be fetched when one is requested.
- */
-public interface PasswordFinder
-{
-    public char[] getPassword();
-}
diff --git a/src/main/java/org/bouncycastle/util/Arrays.java b/src/main/java/org/bouncycastle/util/Arrays.java
index 9d6a43b..4564b68 100644
--- a/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/src/main/java/org/bouncycastle/util/Arrays.java
@@ -1,5 +1,7 @@
 package org.bouncycastle.util;
 
+import java.math.BigInteger;
+
 /**
  * General array utilities.
  */
@@ -167,6 +169,66 @@
         return true;
     }
 
+    public static boolean areEqual(
+        long[]  a,
+        long[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean areEqual(
+        BigInteger[]  a,
+        BigInteger[]  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]))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     public static void fill(
         byte[] array,
         byte value)
@@ -197,6 +259,16 @@
         }
     }
 
+    public static void fill(
+        int[] array,
+        int value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+    
     public static int hashCode(byte[] data)
     {
         if (data == null)
@@ -216,6 +288,63 @@
         return hc;
     }
 
+    public static int hashCode(char[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(int[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(BigInteger[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i].hashCode();
+        }
+
+        return hc;
+    }
+
     public static byte[] clone(byte[] data)
     {
         if (data == null)
@@ -241,4 +370,163 @@
 
         return copy;
     }
+
+    public static BigInteger[] clone(BigInteger[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        BigInteger[] copy = new BigInteger[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static byte[] copyOf(byte[] data, int newLength)
+    {
+        byte[] tmp = new byte[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static int[] copyOf(int[] data, int newLength)
+    {
+        int[] tmp = new int[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static long[] copyOf(long[] data, int newLength)
+    {
+        long[] tmp = new long[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static BigInteger[] copyOf(BigInteger[] data, int newLength)
+    {
+        BigInteger[] tmp = new BigInteger[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static byte[] copyOfRange(byte[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        byte[] tmp = new byte[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    public static int[] copyOfRange(int[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        int[] tmp = new int[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    public static long[] copyOfRange(long[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        long[] tmp = new long[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        BigInteger[] tmp = new BigInteger[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    private static int getLength(int from, int to)
+    {
+        int newLength = to - from;
+        if (newLength < 0)
+        {
+            throw new IllegalArgumentException(from + " > " + to);
+        }
+        return newLength;
+    }
 }
diff --git a/src/main/java/org/bouncycastle/util/Strings.java b/src/main/java/org/bouncycastle/util/Strings.java
index 0c081f7..7f67404 100644
--- a/src/main/java/org/bouncycastle/util/Strings.java
+++ b/src/main/java/org/bouncycastle/util/Strings.java
@@ -1,6 +1,8 @@
 package org.bouncycastle.util;
 
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.Vector;
 
 public final class Strings
@@ -88,6 +90,22 @@
     public static byte[] toUTF8ByteArray(char[] string)
     {
         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        try
+        {
+            toUTF8ByteArray(string, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("cannot encode string to byte array!");
+        }
+        
+        return bOut.toByteArray();
+    }
+
+    public static void toUTF8ByteArray(char[] string, OutputStream sOut)
+        throws IOException
+    {
         char[] c = string;
         int i = 0;
 
@@ -97,12 +115,12 @@
 
             if (ch < 0x0080)
             {
-                bOut.write(ch);
+                sOut.write(ch);
             }
             else if (ch < 0x0800)
             {
-                bOut.write(0xc0 | (ch >> 6));
-                bOut.write(0x80 | (ch & 0x3f));
+                sOut.write(0xc0 | (ch >> 6));
+                sOut.write(0x80 | (ch & 0x3f));
             }
             // surrogate pair
             else if (ch >= 0xD800 && ch <= 0xDFFF)
@@ -123,24 +141,22 @@
                     throw new IllegalStateException("invalid UTF-16 codepoint");
                 }
                 int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
-                bOut.write(0xf0 | (codePoint >> 18));
-                bOut.write(0x80 | ((codePoint >> 12) & 0x3F));
-                bOut.write(0x80 | ((codePoint >> 6) & 0x3F));
-                bOut.write(0x80 | (codePoint & 0x3F));
+                sOut.write(0xf0 | (codePoint >> 18));
+                sOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+                sOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+                sOut.write(0x80 | (codePoint & 0x3F));
             }
             else
             {
-                bOut.write(0xe0 | (ch >> 12));
-                bOut.write(0x80 | ((ch >> 6) & 0x3F));
-                bOut.write(0x80 | (ch & 0x3F));
+                sOut.write(0xe0 | (ch >> 12));
+                sOut.write(0x80 | ((ch >> 6) & 0x3F));
+                sOut.write(0x80 | (ch & 0x3F));
             }
 
             i++;
         }
-        
-        return bOut.toByteArray();
     }
-    
+
     /**
      * A locale independent version of toUpperCase.
      * 
@@ -225,6 +241,35 @@
         return bytes;
     }
 
+    /**
+     * Convert an array of 8 bit characters into a string.
+     *
+     * @param bytes 8 bit characters.
+     * @return resulting String.
+     */
+    public static String fromByteArray(byte[] bytes)
+    {
+        return new String(asCharArray(bytes));
+    }
+
+    /**
+     * Do a simple conversion of an array of 8 bit characters into a string.
+     *
+     * @param bytes 8 bit characters.
+     * @return resulting String.
+     */
+    public static char[] asCharArray(byte[] bytes)
+    {
+        char[] chars = new char[bytes.length];
+
+        for (int i = 0; i != chars.length; i++)
+        {
+            chars[i] = (char)(bytes[i] & 0xff);
+        }
+
+        return chars;
+    }
+
     public static String[] split(String input, char delimiter)
     {
         Vector           v = new Vector();
diff --git a/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java b/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java
new file mode 100644
index 0000000..a4919cd
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class TeeOutputStream
+    extends OutputStream
+{
+    private OutputStream output1;
+    private OutputStream output2;
+
+    public TeeOutputStream(OutputStream output1, OutputStream output2)
+    {
+        this.output1 = output1;
+        this.output2 = output2;
+    }
+
+    public void write(byte[] buf)
+        throws IOException
+    {
+        this.output1.write(buf);
+        this.output2.write(buf);
+    }
+
+    public void write(byte[] buf, int off, int len)
+        throws IOException
+    {
+        this.output1.write(buf, off, len);
+        this.output2.write(buf, off, len);
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        this.output1.write(b);
+        this.output2.write(b);
+    }
+
+    public void flush()
+        throws IOException
+    {
+        this.output1.flush();
+        this.output2.flush();
+    }
+
+    public void close()
+        throws IOException
+    {
+        this.output1.close();
+        this.output2.close();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/util/io/pem/PemReader.java b/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
index 28f777d..7664725 100644
--- a/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
@@ -24,7 +24,12 @@
     {
         String line = readLine();
 
-        if (line != null && line.startsWith(BEGIN))
+        while (line != null && !line.startsWith(BEGIN))
+        {
+            line = readLine();
+        }
+
+        if (line != null)
         {
             line = line.substring(BEGIN.length());
             int index = line.indexOf('-');
diff --git a/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java b/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
index 2290484..b00cd1d 100644
--- a/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
+++ b/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
@@ -15,8 +15,9 @@
 import javax.security.auth.x500.X500Principal;
 
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.GeneralName;
@@ -60,8 +61,8 @@
         BigInteger serialNumber)
     {
         holder = new org.bouncycastle.asn1.x509.Holder(new IssuerSerial(
-            new GeneralNames(new DERSequence(new GeneralName(issuerName))),
-            new DERInteger(serialNumber)));
+            GeneralNames.getInstance(new DERSequence(new GeneralName(issuerName))),
+            new ASN1Integer(serialNumber)));
     }
 
     public AttributeCertificateHolder(X500Principal issuerName,
@@ -85,7 +86,7 @@
         }
 
         holder = new Holder(new IssuerSerial(generateGeneralNames(name),
-            new DERInteger(cert.getSerialNumber())));
+            new ASN1Integer(cert.getSerialNumber())));
     }
 
     public AttributeCertificateHolder(X509Principal principal)
@@ -125,7 +126,7 @@
         String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
     {
         holder = new Holder(new ObjectDigestInfo(digestedObjectType,
-            otherObjectTypeID, new AlgorithmIdentifier(digestAlgorithm), Arrays
+            new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
                 .clone(objectDigest)));
     }
 
@@ -200,7 +201,7 @@
 
     private GeneralNames generateGeneralNames(X509Principal principal)
     {
-        return new GeneralNames(new DERSequence(new GeneralName(principal)));
+        return GeneralNames.getInstance(new DERSequence(new GeneralName(principal)));
     }
 
     private boolean matchesDN(X509Principal subject, GeneralNames targets)
@@ -215,7 +216,7 @@
             {
                 try
                 {
-                    if (new X509Principal(((ASN1Encodable)gn.getName())
+                    if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
                         .getEncoded()).equals(subject))
                     {
                         return true;
@@ -241,7 +242,7 @@
                 try
                 {
                     l.add(new X500Principal(
-                        ((ASN1Encodable)names[i].getName()).getEncoded()));
+                        ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
                 }
                 catch (IOException e)
                 {
diff --git a/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java b/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
index 0c88b3f..3a34208 100644
--- a/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
+++ b/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
@@ -46,7 +46,7 @@
 
     public AttributeCertificateIssuer(X509Principal principal)
     {
-        form = new V2Form(new GeneralNames(new DERSequence(new GeneralName(principal))));
+        form = new V2Form(GeneralNames.getInstance(new DERSequence(new GeneralName(principal))));
     }
 
     private Object[] getNames()
@@ -73,7 +73,7 @@
                 try
                 {
                     l.add(new X500Principal(
-                        ((ASN1Encodable)names[i].getName()).getEncoded()));
+                        ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
                 }
                 catch (IOException e)
                 {
@@ -119,7 +119,7 @@
             {
                 try
                 {
-                    if (new X500Principal(((ASN1Encodable)gn.getName()).getEncoded()).equals(subject))
+                    if (new X500Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
                     {
                         return true;
                     }
diff --git a/src/main/java/org/bouncycastle/x509/X509Attribute.java b/src/main/java/org/bouncycastle/x509/X509Attribute.java
index f4c65ab..95da292 100644
--- a/src/main/java/org/bouncycastle/x509/X509Attribute.java
+++ b/src/main/java/org/bouncycastle/x509/X509Attribute.java
@@ -2,9 +2,10 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSet;
 import org.bouncycastle.asn1.x509.Attribute;
 
@@ -12,7 +13,7 @@
  * Class for carrying the values in an X.509 Attribute.
  */
 public class X509Attribute
-    extends ASN1Encodable
+    extends ASN1Object
 {
     Attribute    attr;
     
@@ -36,7 +37,7 @@
         String          oid,
         ASN1Encodable   value)
     {
-        this.attr = new Attribute(new DERObjectIdentifier(oid), new DERSet(value));
+        this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
     }
     
     /**
@@ -50,7 +51,7 @@
         String              oid,
         ASN1EncodableVector value)
     {
-        this.attr = new Attribute(new DERObjectIdentifier(oid), new DERSet(value));
+        this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
     }
     
     public String getOID()
@@ -71,8 +72,8 @@
         return values;
     }
     
-    public DERObject toASN1Object()
+    public ASN1Primitive toASN1Primitive()
     {
-        return attr.toASN1Object();
+        return attr.toASN1Primitive();
     }
 }
diff --git a/src/main/java/org/bouncycastle/x509/X509Util.java b/src/main/java/org/bouncycastle/x509/X509Util.java
index 9ea50b4..202bd4b 100644
--- a/src/main/java/org/bouncycastle/x509/X509Util.java
+++ b/src/main/java/org/bouncycastle/x509/X509Util.java
@@ -21,8 +21,8 @@
 import javax.security.auth.x500.X500Principal;
 
 import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
@@ -30,7 +30,9 @@
 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.jce.X509Principal;
@@ -164,8 +166,8 @@
         return new RSASSAPSSparams(
             hashAlgId,
             new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
-            new DERInteger(saltSize),
-            new DERInteger(1));
+            new ASN1Integer(saltSize),
+            new ASN1Integer(1));
     }
 
     static DERObjectIdentifier getAlgorithmOID(
@@ -194,7 +196,7 @@
 
         if (params.containsKey(algorithmName))
         {
-            return new AlgorithmIdentifier(sigOid, (DEREncodable)params.get(algorithmName));
+            return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
         }
         else
         {
@@ -265,7 +267,7 @@
             sig.initSign(key);
         }
 
-        sig.update(object.getEncoded(ASN1Encodable.DER));
+        sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
 
         return sig.sign();
     }
@@ -297,7 +299,7 @@
             sig.initSign(key);
         }
 
-        sig.update(object.getEncoded(ASN1Encodable.DER));
+        sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
 
         return sig.sign();
     }
diff --git a/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java b/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
index 5e99e76..5703dc8 100644
--- a/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
@@ -21,14 +21,14 @@
 
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.TBSCertificate;
 import org.bouncycastle.asn1.x509.Time;
 import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
 import org.bouncycastle.asn1.x509.X509CertificateStructure;
@@ -71,7 +71,7 @@
             throw new IllegalArgumentException("serial number must be a positive integer");
         }
         
-        tbsGen.setSerialNumber(new DERInteger(serialNumber));
+        tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
     }
 
     /**
@@ -292,7 +292,7 @@
         SecureRandom    random)
         throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
     {
-        TBSCertificateStructure tbsCert = tbsGen.generateTBSCertificate();
+        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
         byte[] signature;
 
         try
@@ -331,7 +331,7 @@
         SecureRandom    random)
         throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
     {
-        TBSCertificateStructure tbsCert = tbsGen.generateTBSCertificate();
+        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
         byte[] signature;
 
         try
@@ -346,7 +346,7 @@
         return generateJcaObject(tbsCert, signature);
     }
 
-    private X509Certificate generateJcaObject(TBSCertificateStructure tbsCert, byte[] signature)
+    private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
         throws CertificateEncodingException
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
diff --git a/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java b/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
index 4d40dd9..14db8ea 100644
--- a/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
+++ b/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
@@ -22,13 +22,14 @@
 import java.util.Set;
 
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.x509.AttributeCertificate;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
 import org.bouncycastle.util.Arrays;
 
 /**
@@ -206,17 +207,17 @@
 
     public byte[] getExtensionValue(String oid) 
     {
-        X509Extensions  extensions = cert.getAcinfo().getExtensions();
+        Extensions extensions = cert.getAcinfo().getExtensions();
 
         if (extensions != null)
         {
-            X509Extension   ext = extensions.getExtension(new DERObjectIdentifier(oid));
+            Extension ext = extensions.getExtension(new ASN1ObjectIdentifier(oid));
 
             if (ext != null)
             {
                 try
                 {
-                    return ext.getValue().getEncoded(ASN1Encodable.DER);
+                    return ext.getExtnValue().getEncoded(ASN1Encoding.DER);
                 }
                 catch (Exception e)
                 {
@@ -231,7 +232,7 @@
     private Set getExtensionOIDs(
         boolean critical) 
     {
-        X509Extensions  extensions = cert.getAcinfo().getExtensions();
+        Extensions  extensions = cert.getAcinfo().getExtensions();
 
         if (extensions != null)
         {
@@ -240,8 +241,8 @@
 
             while (e.hasMoreElements())
             {
-                DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
-                X509Extension       ext = extensions.getExtension(oid);
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                Extension            ext = extensions.getExtension(oid);
 
                 if (ext.isCritical() == critical)
                 {
diff --git a/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java b/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
index 1ac395c..870ba4f 100644
--- a/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
@@ -21,14 +21,14 @@
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.TBSCertificate;
 import org.bouncycastle.asn1.x509.Time;
 import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
 import org.bouncycastle.asn1.x509.X509CertificateStructure;
@@ -76,7 +76,7 @@
             throw new IllegalArgumentException("serial number must be a positive integer");
         }
         
-        tbsGen.setSerialNumber(new DERInteger(serialNumber));
+        tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
     }
 
     /**
@@ -226,7 +226,7 @@
     public void addExtension(
         String          oid,
         boolean         critical,
-        DEREncodable    value)
+        ASN1Encodable    value)
     {
         this.addExtension(new DERObjectIdentifier(oid), critical, value);
     }
@@ -237,9 +237,9 @@
     public void addExtension(
         DERObjectIdentifier oid,
         boolean             critical,
-        DEREncodable        value)
+        ASN1Encodable        value)
     {
-        extGenerator.addExtension(oid, critical,  value);
+        extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical,  value);
     }
 
     /**
@@ -263,7 +263,7 @@
         boolean             critical,
         byte[]              value)
     {
-        extGenerator.addExtension(oid, critical, value);
+        extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
     }
 
     /**
@@ -426,7 +426,7 @@
         SecureRandom    random)
         throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
     {
-        TBSCertificateStructure tbsCert = generateTbsCert();
+        TBSCertificate tbsCert = generateTbsCert();
         byte[] signature;
 
         try
@@ -471,7 +471,7 @@
         SecureRandom    random)
         throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
     {
-        TBSCertificateStructure tbsCert = generateTbsCert();
+        TBSCertificate tbsCert = generateTbsCert();
         byte[] signature;
 
         try
@@ -493,7 +493,7 @@
         }
     }
 
-    private TBSCertificateStructure generateTbsCert()
+    private TBSCertificate generateTbsCert()
     {
         if (!extGenerator.isEmpty())
         {
@@ -503,7 +503,7 @@
         return tbsGen.generateTBSCertificate();
     }
 
-    private X509Certificate generateJcaObject(TBSCertificateStructure tbsCert, byte[] signature)
+    private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
         throws CertificateParsingException
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
diff --git a/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
index 8de75d2..2164d1f 100644
--- a/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
+++ b/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
@@ -10,6 +10,7 @@
 import org.bouncycastle.asn1.ASN1OctetString;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.Extension;
 import org.bouncycastle.asn1.x509.GeneralName;
 import org.bouncycastle.asn1.x509.GeneralNames;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -19,6 +20,7 @@
 
 /**
  * A high level authority key identifier.
+ * @deprecated use JcaX509ExtensionUtils and AuthorityKeyIdentifier.getInstance()
  */
 public class AuthorityKeyIdentifierStructure
     extends AuthorityKeyIdentifier
@@ -40,6 +42,7 @@
      * Constructor which will take an extension
      *
      * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+     * @deprecated use constructor that takes Extension
      */
     public AuthorityKeyIdentifierStructure(
         X509Extension extension)
@@ -47,6 +50,17 @@
         super((ASN1Sequence)extension.getParsedValue());
     }
 
+    /**
+     * Constructor which will take an extension
+     *
+     * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+     */
+    public AuthorityKeyIdentifierStructure(
+        Extension extension)
+    {
+        super((ASN1Sequence)extension.getParsedValue());
+    }
+
     private static ASN1Sequence fromCertificate(
         X509Certificate certificate)
         throws CertificateParsingException
diff --git a/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java b/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
index 8f54c6e..2c7afd3 100644
--- a/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
+++ b/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
@@ -10,6 +10,7 @@
 
 /**
  * A high level subject key identifier.
+ * @deprecated use JcaX509ExtensionUtils andSubjectKeyIdentifier.getInstance()
  */
 public class SubjectKeyIdentifierStructure
     extends SubjectKeyIdentifier
diff --git a/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java b/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
index 0acb666..048f31b 100644
--- a/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
+++ b/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
@@ -9,32 +9,32 @@
 import java.util.Enumeration;
 import java.util.List;
 
-import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1String;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.asn1.x509.X509Extension;
 
 
 public class X509ExtensionUtil
 {
-    public static ASN1Object fromExtensionValue(
+    public static ASN1Primitive fromExtensionValue(
         byte[]  encodedValue) 
         throws IOException
     {
-        ASN1OctetString octs = (ASN1OctetString)ASN1Object.fromByteArray(encodedValue);
+        ASN1OctetString octs = (ASN1OctetString)ASN1Primitive.fromByteArray(encodedValue);
         
-        return ASN1Object.fromByteArray(octs.getOctets());
+        return ASN1Primitive.fromByteArray(octs.getOctets());
     }
 
     public static Collection getIssuerAlternativeNames(X509Certificate cert)
             throws CertificateParsingException
     {
-        byte[] extVal = cert.getExtensionValue(X509Extensions.IssuerAlternativeName.getId());
+        byte[] extVal = cert.getExtensionValue(X509Extension.issuerAlternativeName.getId());
 
         return getAlternativeNames(extVal);
     }
@@ -42,7 +42,7 @@
     public static Collection getSubjectAlternativeNames(X509Certificate cert)
             throws CertificateParsingException
     {        
-        byte[] extVal = cert.getExtensionValue(X509Extensions.SubjectAlternativeName.getId());
+        byte[] extVal = cert.getExtensionValue(X509Extension.subjectAlternativeName.getId());
 
         return getAlternativeNames(extVal);
     }
@@ -70,10 +70,10 @@
                 case GeneralName.ediPartyName:
                 case GeneralName.x400Address:
                 case GeneralName.otherName:
-                    list.add(genName.getName().getDERObject());
+                    list.add(genName.getName().toASN1Primitive());
                     break;
                 case GeneralName.directoryName:
-                    list.add(X509Name.getInstance(genName.getName()).toString());
+                    list.add(X500Name.getInstance(genName.getName()).toString());
                     break;
                 case GeneralName.dNSName:
                 case GeneralName.rfc822Name:
@@ -81,7 +81,7 @@
                     list.add(((ASN1String)genName.getName()).getString());
                     break;
                 case GeneralName.registeredID:
-                    list.add(DERObjectIdentifier.getInstance(genName.getName()).getId());
+                    list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
                     break;
                 case GeneralName.iPAddress:
                     list.add(DEROctetString.getInstance(genName.getName()).getOctets());