Bouncy Castle: Add support for PBES2 encrypted KeyStores.

Cherry-pick notes: Will also be cherry-picking https://android-review.git.corp.google.com/q/topic:%22bcprivate_exceptions%22 which hides exceptions from the private provider better.  Aim is to get both topics into the April mainline train.

Adds a private sub-Provider to BouncyCastleProvider which allows BC's
PKCS12 implementation to continue using its own implementations of some Macs and Ciphers which support PBES2.

These implementions are not exposed to apps and are only used
from BC internals.

Bug: 230750823
Test: atest
CtsLibcoreTestCases:tests.targets.security.KeyStorePkcs7FormatTest
Change-Id: Ic505d0259d16cdc66f9776e818efa20ed97aa32b
Merged-In: Ic505d0259d16cdc66f9776e818efa20ed97aa32b
(cherry picked from commit 4fae1c6cb82e4b3e7d51e38ce0e3d7a4f22a0939)
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
index 9818f86..831b497 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -54,4 +54,11 @@
     AsymmetricKeyInfoConverter getKeyInfoConverter(ASN1ObjectIdentifier oid);
 
     void addAttributes(String key, Map<String, String> attributeMap);
+
+    // BEGIN Android-added: Allow algorithms to be added privately.
+    // See BouncyCastleProvider for details.
+    void addPrivateAlgorithm(String key, String value);
+
+    void addPrivateAlgorithm(String type, ASN1ObjectIdentifier oid, String className);
+    // END Android-added: Allow algorithms to be added privately.
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
index 5c6b699..dd25b0c 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
@@ -76,6 +76,8 @@
             addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha224, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
index 48f99b4..ae4c82f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -101,6 +101,8 @@
             addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha256, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
index 8f08374..b5f269e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -95,6 +95,8 @@
             addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha384, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
index e227620..335d0d6 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -193,6 +193,8 @@
             addHMACAlgorithm(provider, "SHA512/256", PREFIX + "$HashMacT256",  PREFIX + "$KeyGeneratorT256");
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha512, PREFIX + "$HashMac");
         }
     }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index 4c3e480..263c63d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -116,9 +116,12 @@
 {
     static final String PKCS12_MAX_IT_COUNT_PROPERTY = "org.bouncycastle.pkcs12.max_it_count";
 
-    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Android-changed: Use default provider for most JCA algorithms instead of BC.
+    // For the case where we need BC implementations, the BCJcaJceHelper will also search
+    // the list of private implementations help by BouncyCastleProvider.
     // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
     private final JcaJceHelper helper = new DefaultJcaJceHelper();
+    private final JcaJceHelper selfHelper = new BCJcaJceHelper();
 
     private static final int SALT_SIZE = 20;
     private static final int MIN_ITERATIONS = 50 * 1024;
@@ -727,7 +730,9 @@
         PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
         AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
 
-        SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        // Android-Changed: SecretKeyFactory must be from BC due to instanceof logic.
+        // SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        SecretKeyFactory keyFact = selfHelper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
         SecretKey key;
 
         if (func.isDefaultPrf())
@@ -739,7 +744,9 @@
             key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), keySizeProvider.getKeySize(encScheme), func.getPrf()));
         }
 
-        Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+        // Android-Changed: Cipher must be from BC due to use of internal PKCS12Key tyoe.
+        // Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+        Cipher cipher = selfHelper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId());
 
         ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
         if (encParams instanceof ASN1OctetString)
@@ -1781,7 +1788,9 @@
     {
         PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
 
-        Mac mac = helper.createMac(oid.getId());
+        // Android-Changed: Mac must be from BC due to use of internal PKCS12Key tyoe.
+        // Mac mac = helper.createMac(oid.getId());
+        Mac mac = selfHelper.createMac(oid.getId());
         mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams);
         mac.update(data);
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
index e7d3ec2..d25ed90 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -1088,6 +1088,11 @@
             // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
             // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
             // END Android-removed: Unsupported algorithms
+
+            // Android-added: Private implementations needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
         }
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
index 1af79b8..e384134 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
@@ -40,14 +40,14 @@
 
     static
     {
-        // BEGIN Android-removed: Unsupported algorithm
-        /*
-        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA1, Integers.valueOf(PBE.SHA1));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA256, Integers.valueOf(PBE.SHA256));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA224, Integers.valueOf(PBE.SHA224));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA384, Integers.valueOf(PBE.SHA384));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512, Integers.valueOf(PBE.SHA512));
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_256, Integers.valueOf(PBE.SHA3_256));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384));
@@ -62,8 +62,6 @@
 
     }
 
-    // BEGIN Android-removed: Unsupported algorithms
-    /*
     public static class AlgParams
         extends BaseAlgorithmParameters
     {
@@ -146,8 +144,6 @@
             return "PBKDF2 Parameters";
         }
     }
-    */
-    // END Android-removed: Unsupported algorithms
 
     public static class BasePBKDF2
         extends BaseSecretKeyFactory
@@ -273,8 +269,6 @@
         }
     }
 
-    // BEGIN Android-removed: Unsupported algorithms
-    /*
     public static class PBKDF2withUTF8
         extends BasePBKDF2
     {
@@ -284,6 +278,8 @@
         }
     }
 
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
     public static class PBKDF2withSHA224
         extends BasePBKDF2
     {
@@ -614,6 +610,9 @@
             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", PREFIX + "$PBEWithHmacSHA512AndAES_256");
             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
             // END Android-added: Android versions of algorithms.
+            // Android-added: Private implementations needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
+            provider.addPrivateAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.12", "PBKDF2");
         }
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
index 6c38458..9a41d31 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
@@ -1,8 +1,13 @@
 package org.bouncycastle.jcajce.util;
 
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.Security;
 
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
 /**
@@ -38,4 +43,45 @@
     {
         super(getBouncyCastleProvider());
     }
+
+    // BEGIN Android-added: Look up algorithms in private provider if not found in main Provider.
+    //
+    // If code is using a BCJcajceHelper to ensure it gets its implementation from BC, then
+    // also search in the privately provided algorithms if not found in the main set.
+    @Override
+    public Cipher createCipher(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException {
+        try {
+            return super.createCipher(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return Cipher.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    @Override
+    public SecretKeyFactory createSecretKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException {
+        try {
+            return super.createSecretKeyFactory(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return SecretKeyFactory.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    @Override
+    public Mac createMac(String algorithm) throws NoSuchAlgorithmException {
+        try {
+            return super.createMac(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return Mac.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    private Provider getPrivateProvider() {
+        if (provider instanceof BouncyCastleProvider) {
+            return ((BouncyCastleProvider) provider).getPrivateProvider();
+        }
+        throw new IllegalStateException(); // XXX
+    }
+    // END Android-added: Look up algorithms in private provider if not found in main Provider.
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index bb12aec..7f9285b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -426,4 +426,37 @@
         return converter.generatePrivate(privateKeyInfo);
         */
     }
+
+    // BEGIN Android-added: Allow algorithms to be provided privately for BC internals.
+    //
+    // Algorithms added via these methods are stored in a private instance of PrivateProvider,
+    // which is never added to the system-wide list of installed Providers, and is only
+    // ever searched by BC internal classes which search for algorithms using an instance
+    // of BCJcajceHelper.
+    private static final class PrivateProvider extends Provider {
+        public PrivateProvider() {
+            super("BCPrivate", 1.0, "Android BC private use only");
+        }
+    }
+
+    private final Provider privateProvider = new PrivateProvider();
+
+    public void addPrivateAlgorithm(String key, String value)
+    {
+        if (privateProvider.containsKey(key))
+        {
+            throw new IllegalStateException("duplicate provider key (" + key + ") found");
+        }
+        privateProvider.put(key, value);
+    }
+
+    public void addPrivateAlgorithm(String type, ASN1ObjectIdentifier oid, String className)
+    {
+        addPrivateAlgorithm(type + "." + oid, className);
+    }
+
+    public Provider getPrivateProvider() {
+        return privateProvider;
+    }
+    // END Android-added: Allow algorithms to be provided privately for BC internals.
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
index da69af7..d6dc21e 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -56,4 +56,11 @@
     AsymmetricKeyInfoConverter getKeyInfoConverter(ASN1ObjectIdentifier oid);
 
     void addAttributes(String key, Map<String, String> attributeMap);
+
+    // BEGIN Android-added: Allow algorithms to be added privately.
+    // See BouncyCastleProvider for details.
+    void addPrivateAlgorithm(String key, String value);
+
+    void addPrivateAlgorithm(String type, ASN1ObjectIdentifier oid, String className);
+    // END Android-added: Allow algorithms to be added privately.
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA224.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA224.java
index e9f436a..ff4fde8 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA224.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA224.java
@@ -92,6 +92,8 @@
             addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha224, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA256.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA256.java
index 706d4ab..a4e8a76 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA256.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -115,6 +115,8 @@
             addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha256, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA384.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA384.java
index b7d9716..7ff261e 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA384.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -109,6 +109,8 @@
             addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha384, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA512.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA512.java
index dbd513c..cdc7018 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA512.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -207,6 +207,8 @@
             addHMACAlgorithm(provider, "SHA512/256", PREFIX + "$HashMacT256",  PREFIX + "$KeyGeneratorT256");
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha512, PREFIX + "$HashMac");
         }
     }
 
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index fb5f2fd..06fbb96 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -120,9 +120,12 @@
 {
     static final String PKCS12_MAX_IT_COUNT_PROPERTY = "com.android.org.bouncycastle.pkcs12.max_it_count";
 
-    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Android-changed: Use default provider for most JCA algorithms instead of BC.
+    // For the case where we need BC implementations, the BCJcaJceHelper will also search
+    // the list of private implementations help by BouncyCastleProvider.
     // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
     private final JcaJceHelper helper = new DefaultJcaJceHelper();
+    private final JcaJceHelper selfHelper = new BCJcaJceHelper();
 
     private static final int SALT_SIZE = 20;
     private static final int MIN_ITERATIONS = 50 * 1024;
@@ -731,7 +734,9 @@
         PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
         AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
 
-        SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        // Android-Changed: SecretKeyFactory must be from BC due to instanceof logic.
+        // SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        SecretKeyFactory keyFact = selfHelper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
         SecretKey key;
 
         if (func.isDefaultPrf())
@@ -743,7 +748,9 @@
             key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), keySizeProvider.getKeySize(encScheme), func.getPrf()));
         }
 
-        Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+        // Android-Changed: Cipher must be from BC due to use of internal PKCS12Key tyoe.
+        // Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+        Cipher cipher = selfHelper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId());
 
         ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
         if (encParams instanceof ASN1OctetString)
@@ -1785,7 +1792,9 @@
     {
         PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
 
-        Mac mac = helper.createMac(oid.getId());
+        // Android-Changed: Mac must be from BC due to use of internal PKCS12Key tyoe.
+        // Mac mac = helper.createMac(oid.getId());
+        Mac mac = selfHelper.createMac(oid.getId());
         mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams);
         mac.update(data);
 
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/AES.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/AES.java
index 9e2a493..9684f35 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -1146,6 +1146,11 @@
             // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
             // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
             // END Android-removed: Unsupported algorithms
+
+            // Android-added: Private implementations needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
         }
     }
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
index 2109104..15880ad 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
@@ -44,14 +44,14 @@
 
     static
     {
-        // BEGIN Android-removed: Unsupported algorithm
-        /*
-        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA1, Integers.valueOf(PBE.SHA1));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA256, Integers.valueOf(PBE.SHA256));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA224, Integers.valueOf(PBE.SHA224));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA384, Integers.valueOf(PBE.SHA384));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512, Integers.valueOf(PBE.SHA512));
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_256, Integers.valueOf(PBE.SHA3_256));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384));
@@ -66,8 +66,9 @@
 
     }
 
-    // BEGIN Android-removed: Unsupported algorithms
-    /*
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
     public static class AlgParams
         extends BaseAlgorithmParameters
     {
@@ -150,8 +151,6 @@
             return "PBKDF2 Parameters";
         }
     }
-    */
-    // END Android-removed: Unsupported algorithms
 
     /**
      * @hide This class is not part of the Android public SDK API
@@ -280,8 +279,9 @@
         }
     }
 
-    // BEGIN Android-removed: Unsupported algorithms
-    /*
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
     public static class PBKDF2withUTF8
         extends BasePBKDF2
     {
@@ -291,6 +291,8 @@
         }
     }
 
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
     public static class PBKDF2withSHA224
         extends BasePBKDF2
     {
@@ -687,6 +689,9 @@
             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", PREFIX + "$PBEWithHmacSHA512AndAES_256");
             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
             // END Android-added: Android versions of algorithms.
+            // Android-added: Private implementations needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
+            provider.addPrivateAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.12", "PBKDF2");
         }
     }
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
index 65523d8..b444878 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
@@ -1,9 +1,14 @@
 /* GENERATED SOURCE. DO NOT MODIFY. */
 package com.android.org.bouncycastle.jcajce.util;
 
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.Security;
 
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
 import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
 
 /**
@@ -40,4 +45,45 @@
     {
         super(getBouncyCastleProvider());
     }
+
+    // BEGIN Android-added: Look up algorithms in private provider if not found in main Provider.
+    //
+    // If code is using a BCJcajceHelper to ensure it gets its implementation from BC, then
+    // also search in the privately provided algorithms if not found in the main set.
+    @Override
+    public Cipher createCipher(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException {
+        try {
+            return super.createCipher(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return Cipher.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    @Override
+    public SecretKeyFactory createSecretKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException {
+        try {
+            return super.createSecretKeyFactory(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return SecretKeyFactory.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    @Override
+    public Mac createMac(String algorithm) throws NoSuchAlgorithmException {
+        try {
+            return super.createMac(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return Mac.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    private Provider getPrivateProvider() {
+        if (provider instanceof BouncyCastleProvider) {
+            return ((BouncyCastleProvider) provider).getPrivateProvider();
+        }
+        throw new IllegalStateException(); // XXX
+    }
+    // END Android-added: Look up algorithms in private provider if not found in main Provider.
 }
diff --git a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index 61383ce..798bb8e 100644
--- a/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -429,4 +429,37 @@
         return converter.generatePrivate(privateKeyInfo);
         */
     }
+
+    // BEGIN Android-added: Allow algorithms to be provided privately for BC internals.
+    //
+    // Algorithms added via these methods are stored in a private instance of PrivateProvider,
+    // which is never added to the system-wide list of installed Providers, and is only
+    // ever searched by BC internal classes which search for algorithms using an instance
+    // of BCJcajceHelper.
+    private static final class PrivateProvider extends Provider {
+        public PrivateProvider() {
+            super("BCPrivate", 1.0, "Android BC private use only");
+        }
+    }
+
+    private final Provider privateProvider = new PrivateProvider();
+
+    public void addPrivateAlgorithm(String key, String value)
+    {
+        if (privateProvider.containsKey(key))
+        {
+            throw new IllegalStateException("duplicate provider key (" + key + ") found");
+        }
+        privateProvider.put(key, value);
+    }
+
+    public void addPrivateAlgorithm(String type, ASN1ObjectIdentifier oid, String className)
+    {
+        addPrivateAlgorithm(type + "." + oid, className);
+    }
+
+    public Provider getPrivateProvider() {
+        return privateProvider;
+    }
+    // END Android-added: Allow algorithms to be provided privately for BC internals.
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
index 8f8787f..cd76b86 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -56,4 +56,11 @@
     AsymmetricKeyInfoConverter getKeyInfoConverter(ASN1ObjectIdentifier oid);
 
     void addAttributes(String key, Map<String, String> attributeMap);
+
+    // BEGIN Android-added: Allow algorithms to be added privately.
+    // See BouncyCastleProvider for details.
+    void addPrivateAlgorithm(String key, String value);
+
+    void addPrivateAlgorithm(String type, ASN1ObjectIdentifier oid, String className);
+    // END Android-added: Allow algorithms to be added privately.
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java
index 5b5d951..bac8e72 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java
@@ -92,6 +92,8 @@
             addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha224, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java
index 929364f..a7ab409 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -115,6 +115,8 @@
             addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha256, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java
index 89d1443..5d20951 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -109,6 +109,8 @@
             addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha384, PREFIX + "$HashMac");
         }
     }
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java
index b726dbf..243a306 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -207,6 +207,8 @@
             addHMACAlgorithm(provider, "SHA512/256", PREFIX + "$HashMacT256",  PREFIX + "$KeyGeneratorT256");
             */
             // END Android-removed: Unsupported algorithms
+            // Android-added: Private implementation needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Mac", NISTObjectIdentifiers.id_sha512, PREFIX + "$HashMac");
         }
     }
 
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index d589795..745534d 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -120,9 +120,12 @@
 {
     static final String PKCS12_MAX_IT_COUNT_PROPERTY = "com.android.internal.org.bouncycastle.pkcs12.max_it_count";
 
-    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Android-changed: Use default provider for most JCA algorithms instead of BC.
+    // For the case where we need BC implementations, the BCJcaJceHelper will also search
+    // the list of private implementations help by BouncyCastleProvider.
     // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
     private final JcaJceHelper helper = new DefaultJcaJceHelper();
+    private final JcaJceHelper selfHelper = new BCJcaJceHelper();
 
     private static final int SALT_SIZE = 20;
     private static final int MIN_ITERATIONS = 50 * 1024;
@@ -731,7 +734,9 @@
         PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
         AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
 
-        SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        // Android-Changed: SecretKeyFactory must be from BC due to instanceof logic.
+        // SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        SecretKeyFactory keyFact = selfHelper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
         SecretKey key;
 
         if (func.isDefaultPrf())
@@ -743,7 +748,9 @@
             key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), keySizeProvider.getKeySize(encScheme), func.getPrf()));
         }
 
-        Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+        // Android-Changed: Cipher must be from BC due to use of internal PKCS12Key tyoe.
+        // Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+        Cipher cipher = selfHelper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId());
 
         ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
         if (encParams instanceof ASN1OctetString)
@@ -1785,7 +1792,9 @@
     {
         PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
 
-        Mac mac = helper.createMac(oid.getId());
+        // Android-Changed: Mac must be from BC due to use of internal PKCS12Key tyoe.
+        // Mac mac = helper.createMac(oid.getId());
+        Mac mac = selfHelper.createMac(oid.getId());
         mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams);
         mac.update(data);
 
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java
index 55510fd..056faae 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -1146,6 +1146,11 @@
             // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
             // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
             // END Android-removed: Unsupported algorithms
+
+            // Android-added: Private implementations needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+            provider.addPrivateAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
         }
     }
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
index ab218e1..63824db 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
@@ -44,14 +44,14 @@
 
     static
     {
-        // BEGIN Android-removed: Unsupported algorithm
-        /*
-        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA1, Integers.valueOf(PBE.SHA1));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA256, Integers.valueOf(PBE.SHA256));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA224, Integers.valueOf(PBE.SHA224));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA384, Integers.valueOf(PBE.SHA384));
         prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512, Integers.valueOf(PBE.SHA512));
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_256, Integers.valueOf(PBE.SHA3_256));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224));
         prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384));
@@ -66,8 +66,9 @@
 
     }
 
-    // BEGIN Android-removed: Unsupported algorithms
-    /*
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
     public static class AlgParams
         extends BaseAlgorithmParameters
     {
@@ -150,8 +151,6 @@
             return "PBKDF2 Parameters";
         }
     }
-    */
-    // END Android-removed: Unsupported algorithms
 
     /**
      * @hide This class is not part of the Android public SDK API
@@ -280,8 +279,9 @@
         }
     }
 
-    // BEGIN Android-removed: Unsupported algorithms
-    /*
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
     public static class PBKDF2withUTF8
         extends BasePBKDF2
     {
@@ -291,6 +291,8 @@
         }
     }
 
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
     public static class PBKDF2withSHA224
         extends BasePBKDF2
     {
@@ -687,6 +689,9 @@
             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", PREFIX + "$PBEWithHmacSHA512AndAES_256");
             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
             // END Android-added: Android versions of algorithms.
+            // Android-added: Private implementations needed to support PBKDF2 with PKCS#12
+            provider.addPrivateAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
+            provider.addPrivateAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.12", "PBKDF2");
         }
     }
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
index 15130f2..7b7c6cb 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
@@ -1,9 +1,14 @@
 /* GENERATED SOURCE. DO NOT MODIFY. */
 package com.android.internal.org.bouncycastle.jcajce.util;
 
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.Security;
 
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
 import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
 
 /**
@@ -40,4 +45,45 @@
     {
         super(getBouncyCastleProvider());
     }
+
+    // BEGIN Android-added: Look up algorithms in private provider if not found in main Provider.
+    //
+    // If code is using a BCJcajceHelper to ensure it gets its implementation from BC, then
+    // also search in the privately provided algorithms if not found in the main set.
+    @Override
+    public Cipher createCipher(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException {
+        try {
+            return super.createCipher(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return Cipher.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    @Override
+    public SecretKeyFactory createSecretKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException {
+        try {
+            return super.createSecretKeyFactory(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return SecretKeyFactory.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    @Override
+    public Mac createMac(String algorithm) throws NoSuchAlgorithmException {
+        try {
+            return super.createMac(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return Mac.getInstance(algorithm, getPrivateProvider());
+        }
+    }
+
+    private Provider getPrivateProvider() {
+        if (provider instanceof BouncyCastleProvider) {
+            return ((BouncyCastleProvider) provider).getPrivateProvider();
+        }
+        throw new IllegalStateException(); // XXX
+    }
+    // END Android-added: Look up algorithms in private provider if not found in main Provider.
 }
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index 2f3f1ea..2689da8 100644
--- a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -428,4 +428,37 @@
         return converter.generatePrivate(privateKeyInfo);
         */
     }
+
+    // BEGIN Android-added: Allow algorithms to be provided privately for BC internals.
+    //
+    // Algorithms added via these methods are stored in a private instance of PrivateProvider,
+    // which is never added to the system-wide list of installed Providers, and is only
+    // ever searched by BC internal classes which search for algorithms using an instance
+    // of BCJcajceHelper.
+    private static final class PrivateProvider extends Provider {
+        public PrivateProvider() {
+            super("BCPrivate", 1.0, "Android BC private use only");
+        }
+    }
+
+    private final Provider privateProvider = new PrivateProvider();
+
+    public void addPrivateAlgorithm(String key, String value)
+    {
+        if (privateProvider.containsKey(key))
+        {
+            throw new IllegalStateException("duplicate provider key (" + key + ") found");
+        }
+        privateProvider.put(key, value);
+    }
+
+    public void addPrivateAlgorithm(String type, ASN1ObjectIdentifier oid, String className)
+    {
+        addPrivateAlgorithm(type + "." + oid, className);
+    }
+
+    public Provider getPrivateProvider() {
+        return privateProvider;
+    }
+    // END Android-added: Allow algorithms to be provided privately for BC internals.
 }