PBE.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1package org.bouncycastle.jcajce.provider.symmetric.util;
2
3import java.security.spec.AlgorithmParameterSpec;
4
5import javax.crypto.spec.PBEKeySpec;
6import javax.crypto.spec.PBEParameterSpec;
7
8import org.bouncycastle.crypto.CipherParameters;
9import org.bouncycastle.crypto.PBEParametersGenerator;
10// BEGIN android-removed
11// import org.bouncycastle.crypto.digests.GOST3411Digest;
12// import org.bouncycastle.crypto.digests.MD2Digest;
13// import org.bouncycastle.crypto.digests.MD5Digest;
14// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
15// import org.bouncycastle.crypto.digests.SHA1Digest;
16// import org.bouncycastle.crypto.digests.SHA256Digest;
17// import org.bouncycastle.crypto.digests.TigerDigest;
18// END android-removed
19// BEGIN android-added
20import org.bouncycastle.crypto.digests.AndroidDigestFactory;
21// END android-added
22import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
23import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
24import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
25import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
26import org.bouncycastle.crypto.params.DESParameters;
27import org.bouncycastle.crypto.params.KeyParameter;
28import org.bouncycastle.crypto.params.ParametersWithIV;
29
30public interface PBE
31{
32    //
33    // PBE Based encryption constants - by default we do PKCS12 with SHA-1
34    //
35    static final int        MD5          = 0;
36    static final int        SHA1         = 1;
37    // BEGIN android-removed
38    // static final int        RIPEMD160    = 2;
39    // static final int        TIGER        = 3;
40    // END android-removed
41    static final int        SHA256       = 4;
42    // BEGIN android-removed
43    // static final int        MD2          = 5;
44    // static final int        GOST3411     = 6;
45    // END android-removed
46
47    static final int        PKCS5S1      = 0;
48    static final int        PKCS5S2      = 1;
49    static final int        PKCS12       = 2;
50    static final int        OPENSSL      = 3;
51    static final int        PKCS5S1_UTF8 = 4;
52    static final int        PKCS5S2_UTF8 = 5;
53
54    /**
55     * uses the appropriate mixer to generate the key and IV if necessary.
56     */
57    static class Util
58    {
59        static private PBEParametersGenerator makePBEGenerator(
60            int                     type,
61            int                     hash)
62        {
63            PBEParametersGenerator  generator;
64
65            if (type == PKCS5S1 || type == PKCS5S1_UTF8)
66            {
67                switch (hash)
68                {
69                // BEGIN android-removed
70                // case MD2:
71                //     generator = new PKCS5S1ParametersGenerator(new MD2Digest());
72                //     break;
73                // END android-removed
74                case MD5:
75                    // BEGIN android-changed
76                    generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getMD5());
77                    // END android-changed
78                    break;
79                case SHA1:
80                    // BEGIN android-changed
81                    generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getSHA1());
82                    // END android-changed
83                    break;
84                default:
85                    throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
86                }
87            }
88            else if (type == PKCS5S2 || type == PKCS5S2_UTF8)
89            {
90                switch (hash)
91                {
92                // BEGIN android-removed
93                // case MD2:
94                //     generator = new PKCS5S2ParametersGenerator(new MD2Digest());
95                //     break;
96                // END android-removed
97                case MD5:
98                    // BEGIN android-changed
99                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getMD5());
100                    // END android-changed
101                    break;
102                case SHA1:
103                    // BEGIN android-changed
104                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA1());
105                    // END android-changed
106                    break;
107                // BEGIN android-removed
108                // case RIPEMD160:
109                //     generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
110                //     break;
111                // case TIGER:
112                //     generator = new PKCS5S2ParametersGenerator(new TigerDigest());
113                //     break;
114                // END android-removed
115                case SHA256:
116                    // BEGIN android-changed
117                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA256());
118                    // END android-changed
119                    break;
120                // BEGIN android-removed
121                // case GOST3411:
122                //     generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
123                //     break;
124                // END android-removed
125                default:
126                    throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption.");
127                }
128            }
129            else if (type == PKCS12)
130            {
131                switch (hash)
132                {
133                // BEGIN android-removed
134                // case MD2:
135                //     generator = new PKCS12ParametersGenerator(new MD2Digest());
136                //     break;
137                // END android-removed
138                case MD5:
139                    // BEGIN android-changed
140                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getMD5());
141                    // END android-changed
142                    break;
143                case SHA1:
144                    // BEGIN android-changed
145                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA1());
146                    // END android-changed
147                    break;
148                // BEGIN android-removed
149                // case RIPEMD160:
150                //     generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
151                //     break;
152                // case TIGER:
153                //     generator = new PKCS12ParametersGenerator(new TigerDigest());
154                //     break;
155                // END android-removed
156                case SHA256:
157                    // BEGIN android-changed
158                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA256());
159                    // END android-changed
160                    break;
161                // BEGIN android-removed
162                // case GOST3411:
163                //     generator = new PKCS12ParametersGenerator(new GOST3411Digest());
164                //     break;
165                // END android-removed
166                default:
167                    throw new IllegalStateException("unknown digest scheme for PBE encryption.");
168                }
169            }
170            else
171            {
172                generator = new OpenSSLPBEParametersGenerator();
173            }
174
175            return generator;
176        }
177
178        /**
179         * construct a key and iv (if necessary) suitable for use with a
180         * Cipher.
181         */
182        public static CipherParameters makePBEParameters(
183            BCPBEKey pbeKey,
184            AlgorithmParameterSpec spec,
185            String targetAlgorithm)
186        {
187            if ((spec == null) || !(spec instanceof PBEParameterSpec))
188            {
189                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
190            }
191
192            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
193            PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
194            byte[]                  key = pbeKey.getEncoded();
195            CipherParameters        param;
196
197            if (pbeKey.shouldTryWrongPKCS12())
198            {
199                key = new byte[2];
200            }
201
202            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
203
204            if (pbeKey.getIvSize() != 0)
205            {
206                param = generator.generateDerivedParameters(pbeKey.getKeySize(), pbeKey.getIvSize());
207            }
208            else
209            {
210                param = generator.generateDerivedParameters(pbeKey.getKeySize());
211            }
212
213            if (targetAlgorithm.startsWith("DES"))
214            {
215                if (param instanceof ParametersWithIV)
216                {
217                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
218
219                    DESParameters.setOddParity(kParam.getKey());
220                }
221                else
222                {
223                    KeyParameter    kParam = (KeyParameter)param;
224
225                    DESParameters.setOddParity(kParam.getKey());
226                }
227            }
228
229            for (int i = 0; i != key.length; i++)
230            {
231                key[i] = 0;
232            }
233
234            return param;
235        }
236
237        /**
238         * generate a PBE based key suitable for a MAC algorithm, the
239         * key size is chosen according the MAC size, or the hashing algorithm,
240         * whichever is greater.
241         */
242        public static CipherParameters makePBEMacParameters(
243            BCPBEKey pbeKey,
244            AlgorithmParameterSpec spec)
245        {
246            if ((spec == null) || !(spec instanceof PBEParameterSpec))
247            {
248                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
249            }
250
251            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
252            PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
253            byte[]                  key = pbeKey.getEncoded();
254            CipherParameters        param;
255
256            if (pbeKey.shouldTryWrongPKCS12())
257            {
258                key = new byte[2];
259            }
260
261            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
262
263            param = generator.generateDerivedMacParameters(pbeKey.getKeySize());
264
265            for (int i = 0; i != key.length; i++)
266            {
267                key[i] = 0;
268            }
269
270            return param;
271        }
272
273        /**
274         * construct a key and iv (if necessary) suitable for use with a
275         * Cipher.
276         */
277        public static CipherParameters makePBEParameters(
278            PBEKeySpec keySpec,
279            int type,
280            int hash,
281            int keySize,
282            int ivSize)
283        {
284            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
285            byte[]                  key;
286            CipherParameters        param;
287
288            key = convertPassword(type, keySpec);
289
290            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
291
292            if (ivSize != 0)
293            {
294                param = generator.generateDerivedParameters(keySize, ivSize);
295            }
296            else
297            {
298                param = generator.generateDerivedParameters(keySize);
299            }
300
301            for (int i = 0; i != key.length; i++)
302            {
303                key[i] = 0;
304            }
305
306            return param;
307        }
308
309
310        /**
311         * generate a PBE based key suitable for a MAC algorithm, the
312         * key size is chosen according the MAC size, or the hashing algorithm,
313         * whichever is greater.
314         */
315        public static CipherParameters makePBEMacParameters(
316            PBEKeySpec keySpec,
317            int type,
318            int hash,
319            int keySize)
320        {
321            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
322            byte[]                  key;
323            CipherParameters        param;
324
325            key = convertPassword(type, keySpec);
326
327            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
328
329            param = generator.generateDerivedMacParameters(keySize);
330
331            for (int i = 0; i != key.length; i++)
332            {
333                key[i] = 0;
334            }
335
336            return param;
337        }
338
339        private static byte[] convertPassword(int type, PBEKeySpec keySpec)
340        {
341            byte[] key;
342
343            if (type == PKCS12)
344            {
345                key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
346            }
347            else if (type == PKCS5S2_UTF8 || type == PKCS5S1_UTF8)
348            {
349                key = PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(keySpec.getPassword());
350            }
351            else
352            {
353                key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
354            }
355            return key;
356        }
357    }
358}
359