1 package org.bouncycastle.jcajce.provider.symmetric;
2 
3 import java.io.IOException;
4 import java.security.spec.AlgorithmParameterSpec;
5 import java.security.spec.InvalidKeySpecException;
6 import java.security.spec.InvalidParameterSpecException;
7 import java.security.spec.KeySpec;
8 
9 import javax.crypto.SecretKey;
10 import javax.crypto.spec.PBEKeySpec;
11 import javax.crypto.spec.PBEParameterSpec;
12 
13 import org.bouncycastle.asn1.ASN1Encoding;
14 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
15 import org.bouncycastle.asn1.ASN1Primitive;
16 // BEGIN android-removed
17 // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
18 // END android-removed
19 import org.bouncycastle.asn1.pkcs.PBKDF2Params;
20 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
21 import org.bouncycastle.crypto.CipherParameters;
22 import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
23 import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
24 import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
25 import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
26 import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
27 import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
28 import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
29 
30 public class PBEPBKDF2
31 {
PBEPBKDF2()32     private PBEPBKDF2()
33     {
34 
35     }
36 
37     // BEGIN android-removed
38     // public static class AlgParams
39     //     extends BaseAlgorithmParameters
40     // {
41     //     PBKDF2Params params;
42     //
43     //     protected byte[] engineGetEncoded()
44     //     {
45     //         try
46     //         {
47     //             return params.getEncoded(ASN1Encoding.DER);
48     //         }
49     //         catch (IOException e)
50     //         {
51     //             throw new RuntimeException("Oooops! " + e.toString());
52     //         }
53     //     }
54 
55     //     protected byte[] engineGetEncoded(
56     //         String format)
57     //     {
58     //         if (this.isASN1FormatString(format))
59     //         {
60     //             return engineGetEncoded();
61     //         }
62     //
63     //         return null;
64     //     }
65     //
66     //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
67     //         Class paramSpec)
68     //         throws InvalidParameterSpecException
69     //     {
70     //         if (paramSpec == PBEParameterSpec.class)
71     //         {
72     //             return new PBEParameterSpec(params.getSalt(),
73     //                             params.getIterationCount().intValue());
74     //         }
75     //
76     //         throw new InvalidParameterSpecException("unknown parameter spec passed to PBKDF2 PBE parameters object.");
77     //     }
78     //
79     //     protected void engineInit(
80     //         AlgorithmParameterSpec paramSpec)
81     //         throws InvalidParameterSpecException
82     //     {
83     //         if (!(paramSpec instanceof PBEParameterSpec))
84     //         {
85     //             throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PBKDF2 PBE parameters algorithm parameters object");
86     //         }
87     //
88     //         PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
89     //
90     //         this.params = new PBKDF2Params(pbeSpec.getSalt(),
91     //                             pbeSpec.getIterationCount());
92     //     }
93     //
94     //     protected void engineInit(
95     //         byte[] params)
96     //         throws IOException
97     //     {
98     //         this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
99     //     }
100     //
101     //     protected void engineInit(
102     //         byte[] params,
103     //         String format)
104     //         throws IOException
105     //     {
106     //         if (this.isASN1FormatString(format))
107     //         {
108     //             engineInit(params);
109     //             return;
110     //         }
111     //
112     //         throw new IOException("Unknown parameters format in PBKDF2 parameters object");
113     //     }
114     //
115     //     protected String engineToString()
116     //     {
117     //         return "PBKDF2 Parameters";
118     //     }
119     // }
120     // END android-removed
121 
122     public static class BasePBKDF2
123         extends BaseSecretKeyFactory
124     {
125         private int scheme;
126         // BEGIN ANDROID-ADDED
127         private int keySizeInBits;
128         private int ivSizeInBits;
129         // END ANDROID-ADDED
130         private int defaultDigest;
131 
BasePBKDF2(String name, int scheme)132         public BasePBKDF2(String name, int scheme)
133         {
134             this(name, scheme, SHA1);
135         }
136 
137         // BEGIN ANDROID-CHANGED
138         // Was: public BasePBKDF2(String name, int scheme, int defaultDigest)
BasePBKDF2( String name, int scheme, int digest, int keySizeInBits, int ivSizeInBits)139         private BasePBKDF2(
140                 String name, int scheme, int digest, int keySizeInBits, int ivSizeInBits)
141         // END ANDROID-CHANGED
142         {
143             super(name, PKCSObjectIdentifiers.id_PBKDF2);
144 
145             this.scheme = scheme;
146             // BEGIN ANDROID-ADDED
147             this.keySizeInBits = keySizeInBits;
148             this.ivSizeInBits = ivSizeInBits;
149             // END ANDROID-ADDED
150             this.defaultDigest = digest;
151         }
152 
153         // BEGIN android-added
BasePBKDF2(String name, int scheme, int digest)154         private BasePBKDF2(String name, int scheme, int digest) {
155             this(name, scheme, digest, 0, 0);
156         }
157         // END android-added
158 
engineGenerateSecret( KeySpec keySpec)159         protected SecretKey engineGenerateSecret(
160             KeySpec keySpec)
161             throws InvalidKeySpecException
162         {
163             if (keySpec instanceof PBEKeySpec)
164             {
165                 PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
166 
167                 // BEGIN ANDROID-ADDED
168                 // Allow to specify a key using only the password. The key will be generated later
169                 // when other parameters are known.
170                 if (pbeSpec.getSalt() == null
171                         && pbeSpec.getIterationCount() == 0
172                         && pbeSpec.getKeyLength() == 0
173                         && pbeSpec.getPassword().length > 0
174                         && keySizeInBits != 0) {
175                     return new BCPBEKey(
176                             this.algName, this.algOid, scheme, defaultDigest, keySizeInBits,
177                             ivSizeInBits, pbeSpec,
178                             // cipherParameters, to be generated when the PBE parameters are known.
179                             null);
180                 }
181                 // END ANDROID-ADDED
182 
183                 if (pbeSpec.getSalt() == null)
184                 {
185                     throw new InvalidKeySpecException("missing required salt");
186                 }
187 
188                 if (pbeSpec.getIterationCount() <= 0)
189                 {
190                     throw new InvalidKeySpecException("positive iteration count required: "
191                         + pbeSpec.getIterationCount());
192                 }
193 
194                 if (pbeSpec.getKeyLength() <= 0)
195                 {
196                     throw new InvalidKeySpecException("positive key length required: "
197                         + pbeSpec.getKeyLength());
198                 }
199 
200                 if (pbeSpec.getPassword().length == 0)
201                 {
202                     throw new IllegalArgumentException("password empty");
203                 }
204 
205                 if (pbeSpec instanceof PBKDF2KeySpec)
206                 {
207                     PBKDF2KeySpec spec = (PBKDF2KeySpec)pbeSpec;
208 
209                     int digest = getDigestCode(spec.getPrf().getAlgorithm());
210                     int keySize = pbeSpec.getKeyLength();
211                     int ivSize = -1;    // JDK 1,2 and earlier does not understand simplified version.
212                     CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
213 
214                     return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
215                 }
216                 else
217                 {
218                     int digest = defaultDigest;
219                     int keySize = pbeSpec.getKeyLength();
220                     int ivSize = -1;    // JDK 1,2 and earlier does not understand simplified version.
221                     CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
222 
223                     return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
224                 }
225             }
226 
227             throw new InvalidKeySpecException("Invalid KeySpec");
228         }
229 
230 
getDigestCode(ASN1ObjectIdentifier algorithm)231         private int getDigestCode(ASN1ObjectIdentifier algorithm)
232             throws InvalidKeySpecException
233         {
234             // BEGIN android-removed
235             // if (algorithm.equals(CryptoProObjectIdentifiers.gostR3411Hmac))
236             // {
237             //     return GOST3411;
238             // }
239             // else
240             // END android-removed
241             if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA1))
242             {
243                 return SHA1;
244             }
245             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA256))
246             {
247                 return SHA256;
248             }
249             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA224))
250             {
251                 return SHA224;
252             }
253             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA384))
254             {
255                 return SHA384;
256             }
257             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA512))
258             {
259                 return SHA512;
260             }
261 
262             throw new InvalidKeySpecException("Invalid KeySpec: unknown PRF algorithm " + algorithm);
263         }
264     }
265 
266     // BEGIN android-removed
267     // public static class PBKDF2withUTF8
268     //     extends BasePBKDF2
269     // {
270     //     public PBKDF2withUTF8()
271     //     {
272     //         super("PBKDF2", PKCS5S2_UTF8);
273     //     }
274     // }
275     //
276     // public static class PBKDF2withSHA224
277     //     extends BasePBKDF2
278     // {
279     //     public PBKDF2withSHA224()
280     //     {
281     //         super("PBKDF2", PKCS5S2_UTF8, SHA224);
282     //     }
283     // }
284     //
285     // public static class PBKDF2withSHA256
286     //     extends BasePBKDF2
287     // {
288     //     public PBKDF2withSHA256()
289     //     {
290     //         super("PBKDF2", PKCS5S2_UTF8, SHA256);
291     //     }
292     // }
293     //
294     // public static class PBKDF2withSHA384
295     //     extends BasePBKDF2
296     // {
297     //     public PBKDF2withSHA384()
298     //     {
299     //         super("PBKDF2", PKCS5S2_UTF8, SHA384);
300     //     }
301     // }
302     //
303     // public static class PBKDF2withSHA512
304     //     extends BasePBKDF2
305     // {
306     //     public PBKDF2withSHA512()
307     //     {
308     //         super("PBKDF2", PKCS5S2_UTF8, SHA512);
309     //     }
310     // }
311     //
312     // public static class PBKDF2with8BIT
313     //     extends BasePBKDF2
314     // {
315     //     public PBKDF2with8BIT()
316     //     {
317     //         super("PBKDF2", PKCS5S2);
318     //     }
319     // }
320 
321     // BEGIN android-added
322     public static class BasePBKDF2WithHmacSHA1 extends BasePBKDF2 {
BasePBKDF2WithHmacSHA1(String name, int scheme)323         public BasePBKDF2WithHmacSHA1(String name, int scheme)
324         {
325             super(name, scheme, SHA1);
326         }
327     }
328 
329     public static class PBKDF2WithHmacSHA1UTF8
330             extends BasePBKDF2WithHmacSHA1
331     {
PBKDF2WithHmacSHA1UTF8()332         public PBKDF2WithHmacSHA1UTF8()
333         {
334             super("PBKDF2WithHmacSHA1", PKCS5S2_UTF8);
335         }
336     }
337 
338     public static class PBKDF2WithHmacSHA18BIT
339             extends BasePBKDF2WithHmacSHA1
340     {
PBKDF2WithHmacSHA18BIT()341         public PBKDF2WithHmacSHA18BIT()
342         {
343             super("PBKDF2WithHmacSHA1And8bit", PKCS5S2);
344         }
345     }
346 
347     public static class BasePBKDF2WithHmacSHA224 extends BasePBKDF2 {
BasePBKDF2WithHmacSHA224(String name, int scheme)348         public BasePBKDF2WithHmacSHA224(String name, int scheme)
349         {
350             super(name, scheme, SHA224);
351         }
352     }
353 
354     public static class PBKDF2WithHmacSHA224UTF8
355             extends BasePBKDF2WithHmacSHA224
356     {
PBKDF2WithHmacSHA224UTF8()357         public PBKDF2WithHmacSHA224UTF8()
358         {
359             super("PBKDF2WithHmacSHA224", PKCS5S2_UTF8);
360         }
361     }
362 
363     public static class BasePBKDF2WithHmacSHA256 extends BasePBKDF2 {
BasePBKDF2WithHmacSHA256(String name, int scheme)364         public BasePBKDF2WithHmacSHA256(String name, int scheme)
365         {
366             super(name, scheme, SHA256);
367         }
368     }
369 
370     public static class PBKDF2WithHmacSHA256UTF8
371             extends BasePBKDF2WithHmacSHA256
372     {
PBKDF2WithHmacSHA256UTF8()373         public PBKDF2WithHmacSHA256UTF8()
374         {
375             super("PBKDF2WithHmacSHA256", PKCS5S2_UTF8);
376         }
377     }
378 
379 
380     public static class BasePBKDF2WithHmacSHA384 extends BasePBKDF2 {
BasePBKDF2WithHmacSHA384(String name, int scheme)381         public BasePBKDF2WithHmacSHA384(String name, int scheme)
382         {
383             super(name, scheme, SHA384);
384         }
385     }
386 
387     public static class PBKDF2WithHmacSHA384UTF8
388             extends BasePBKDF2WithHmacSHA384
389     {
PBKDF2WithHmacSHA384UTF8()390         public PBKDF2WithHmacSHA384UTF8()
391         {
392             super("PBKDF2WithHmacSHA384", PKCS5S2_UTF8);
393         }
394     }
395 
396     public static class BasePBKDF2WithHmacSHA512 extends BasePBKDF2 {
BasePBKDF2WithHmacSHA512(String name, int scheme)397         public BasePBKDF2WithHmacSHA512(String name, int scheme)
398         {
399             super(name, scheme, SHA512);
400         }
401     }
402 
403     public static class PBKDF2WithHmacSHA512UTF8
404             extends BasePBKDF2WithHmacSHA512
405     {
PBKDF2WithHmacSHA512UTF8()406         public PBKDF2WithHmacSHA512UTF8()
407         {
408             super("PBKDF2WithHmacSHA512", PKCS5S2_UTF8);
409         }
410     }
411 
412     public static class PBEWithHmacSHA1AndAES_128
413             extends BasePBKDF2 {
PBEWithHmacSHA1AndAES_128()414         public PBEWithHmacSHA1AndAES_128() {
415             super("PBEWithHmacSHA1AndAES_128", PKCS5S2_UTF8, SHA1, 128, 128);
416         }
417     }
418 
419     public static class PBEWithHmacSHA224AndAES_128
420             extends BasePBKDF2 {
PBEWithHmacSHA224AndAES_128()421         public PBEWithHmacSHA224AndAES_128() {
422             super("PBEWithHmacSHA224AndAES_128", PKCS5S2_UTF8, SHA224, 128, 128);
423         }
424     }
425 
426     public static class PBEWithHmacSHA256AndAES_128
427             extends BasePBKDF2 {
PBEWithHmacSHA256AndAES_128()428         public PBEWithHmacSHA256AndAES_128() {
429             super("PBEWithHmacSHA256AndAES_128", PKCS5S2_UTF8, SHA256, 128, 128);
430         }
431     }
432 
433     public static class PBEWithHmacSHA384AndAES_128
434             extends BasePBKDF2 {
PBEWithHmacSHA384AndAES_128()435         public PBEWithHmacSHA384AndAES_128() {
436             super("PBEWithHmacSHA384AndAES_128", PKCS5S2_UTF8, SHA384, 128, 128);
437         }
438     }
439 
440     public static class PBEWithHmacSHA512AndAES_128
441             extends BasePBKDF2 {
PBEWithHmacSHA512AndAES_128()442         public PBEWithHmacSHA512AndAES_128() {
443             super("PBEWithHmacSHA512AndAES_128", PKCS5S2_UTF8, SHA512, 128, 128);
444         }
445     }
446 
447 
448     public static class PBEWithHmacSHA1AndAES_256
449             extends BasePBKDF2 {
PBEWithHmacSHA1AndAES_256()450         public PBEWithHmacSHA1AndAES_256() {
451             super("PBEWithHmacSHA1AndAES_256", PKCS5S2_UTF8, SHA1, 256, 128);
452         }
453     }
454 
455     public static class PBEWithHmacSHA224AndAES_256
456             extends BasePBKDF2 {
PBEWithHmacSHA224AndAES_256()457         public PBEWithHmacSHA224AndAES_256() {
458             super("PBEWithHmacSHA224AndAES_256", PKCS5S2_UTF8, SHA224, 256, 128);
459         }
460     }
461 
462     public static class PBEWithHmacSHA256AndAES_256
463             extends BasePBKDF2 {
PBEWithHmacSHA256AndAES_256()464         public PBEWithHmacSHA256AndAES_256() {
465             super("PBEWithHmacSHA256AndAES_256", PKCS5S2_UTF8, SHA256, 256, 128);
466         }
467     }
468 
469     public static class PBEWithHmacSHA384AndAES_256
470             extends BasePBKDF2 {
PBEWithHmacSHA384AndAES_256()471         public PBEWithHmacSHA384AndAES_256() {
472             super("PBEWithHmacSHA384AndAES_256", PKCS5S2_UTF8, SHA384, 256, 128);
473         }
474     }
475 
476     public static class PBEWithHmacSHA512AndAES_256
477             extends BasePBKDF2 {
PBEWithHmacSHA512AndAES_256()478         public PBEWithHmacSHA512AndAES_256() {
479             super("PBEWithHmacSHA512AndAES_256", PKCS5S2_UTF8, SHA512, 256, 128);
480         }
481     }
482     // END android-added
483 
484     public static class Mappings
485         extends AlgorithmProvider
486     {
487         private static final String PREFIX = PBEPBKDF2.class.getName();
488 
Mappings()489         public Mappings()
490         {
491         }
492 
configure(ConfigurableProvider provider)493         public void configure(ConfigurableProvider provider)
494         {
495             // BEGIN android-comment
496             // Context: many of these services used to be in
497             // com.android.org.bouncycastle.jcajce.provider.digest,SHA1, duplicated with respect to here. This
498             // class (PBEPBKDF2) wasn't present in Android until the upgrade to 1.56. Android added
499             // some other of these services in SHA1 (for fixed key sizes). Then the duplicate
500             // algorithms were removed upstream from SHA1 in
501             // b5634e3155e7fd8688599d3eef8e4f3c8a1db078
502             // . As a result, when adapting BouncyCastle 1.56 from upstream, the Android code that
503             // had been added to SHA1 was moved here, and the rest of the services provided by this
504             // class were commented.
505             // BEGIN android-removed
506             // provider.addAlgorithm("AlgorithmParameters.PBKDF2", PREFIX + "$AlgParams");
507             // provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
508             // provider.addAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
509             // provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1", "PBKDF2");
510             // END android-removed
511             // BEGIN android-changed
512             // Was: provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1ANDUTF8", "PBKDF2");
513             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
514             // END android-changed
515             // BEGin android-removed
516             // provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
517             // provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHASCII", PREFIX + "$PBKDF2with8BIT");
518             // END android-removed
519             // BEGIN android-changed
520             // Was:
521             // provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITH8BIT", "PBKDF2WITHASCII");
522             // provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1AND8BIT", "PBKDF2WITHASCII");
523             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2with8BIT", "PBKDF2WithHmacSHA1And8BIT");
524             // END android-changed
525             // BEGIN android-added
526             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2withASCII", "PBKDF2WithHmacSHA1And8BIT");
527             // BEGIN android-removed
528             // provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA224", PREFIX + "$PBKDF2withSHA224");
529             // provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA256", PREFIX + "$PBKDF2withSHA256");
530             // provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA384", PREFIX + "$PBKDF2withSHA384");
531             // provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512", PREFIX + "$PBKDF2withSHA512");
532             // END android-removed
533             // BEGIN android-added
534             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
535             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA224", PREFIX + "$PBKDF2WithHmacSHA224UTF8");
536             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA256", PREFIX + "$PBKDF2WithHmacSHA256UTF8");
537             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA384", PREFIX + "$PBKDF2WithHmacSHA384UTF8");
538             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA512", PREFIX + "$PBKDF2WithHmacSHA512UTF8");
539             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA1AndAES_128", PREFIX + "$PBEWithHmacSHA1AndAES_128");
540             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA224AndAES_128", PREFIX + "$PBEWithHmacSHA224AndAES_128");
541             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA256AndAES_128", PREFIX + "$PBEWithHmacSHA256AndAES_128");
542             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA384AndAES_128", PREFIX + "$PBEWithHmacSHA384AndAES_128");
543             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_128", PREFIX + "$PBEWithHmacSHA512AndAES_128");
544             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA1AndAES_256", PREFIX + "$PBEWithHmacSHA1AndAES_256");
545             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA224AndAES_256", PREFIX + "$PBEWithHmacSHA224AndAES_256");
546             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA256AndAES_256", PREFIX + "$PBEWithHmacSHA256AndAES_256");
547             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA384AndAES_256", PREFIX + "$PBEWithHmacSHA384AndAES_256");
548             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", PREFIX + "$PBEWithHmacSHA512AndAES_256");
549             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
550             // END android-added
551         }
552     }
553 }
554