Merge "Bouncy Castle: Add support for PBES2 encrypted KeyStores."
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.
 }