1package org.bouncycastle.crypto.generators;
2
3import org.bouncycastle.crypto.CipherParameters;
4import org.bouncycastle.crypto.Digest;
5import org.bouncycastle.crypto.PBEParametersGenerator;
6// BEGIN android-changed
7import org.bouncycastle.crypto.digests.AndroidDigestFactory;
8// END android-changed
9import org.bouncycastle.crypto.params.KeyParameter;
10import org.bouncycastle.crypto.params.ParametersWithIV;
11
12/**
13 * Generator for PBE derived keys and ivs as usd by OpenSSL.
14 * <p>
15 * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
16 * iteration count of 1.
17 * <p>
18 */
19public class OpenSSLPBEParametersGenerator
20    extends PBEParametersGenerator
21{
22    // BEGIN android-changed
23    private Digest  digest = AndroidDigestFactory.getMD5();
24    // END android-changed
25
26    /**
27     * Construct a OpenSSL Parameters generator.
28     */
29    public OpenSSLPBEParametersGenerator()
30    {
31    }
32
33    /**
34     * Initialise - note the iteration count for this algorithm is fixed at 1.
35     *
36     * @param password password to use.
37     * @param salt salt to use.
38     */
39    public void init(
40       byte[] password,
41       byte[] salt)
42    {
43        super.init(password, salt, 1);
44    }
45
46    /**
47     * the derived key function, the ith hash of the password and the salt.
48     */
49    private byte[] generateDerivedKey(
50        int bytesNeeded)
51    {
52        byte[]  buf = new byte[digest.getDigestSize()];
53        byte[]  key = new byte[bytesNeeded];
54        int     offset = 0;
55
56        for (;;)
57        {
58            digest.update(password, 0, password.length);
59            digest.update(salt, 0, salt.length);
60
61            digest.doFinal(buf, 0);
62
63            int len = (bytesNeeded > buf.length) ? buf.length : bytesNeeded;
64            System.arraycopy(buf, 0, key, offset, len);
65            offset += len;
66
67            // check if we need any more
68            bytesNeeded -= len;
69            if (bytesNeeded == 0)
70            {
71                break;
72            }
73
74            // do another round
75            digest.reset();
76            digest.update(buf, 0, buf.length);
77        }
78
79        return key;
80    }
81
82    /**
83     * Generate a key parameter derived from the password, salt, and iteration
84     * count we are currently initialised with.
85     *
86     * @param keySize the size of the key we want (in bits)
87     * @return a KeyParameter object.
88     * @exception IllegalArgumentException if the key length larger than the base hash size.
89     */
90    public CipherParameters generateDerivedParameters(
91        int keySize)
92    {
93        keySize = keySize / 8;
94
95        byte[]  dKey = generateDerivedKey(keySize);
96
97        return new KeyParameter(dKey, 0, keySize);
98    }
99
100    /**
101     * Generate a key with initialisation vector parameter derived from
102     * the password, salt, and iteration count we are currently initialised
103     * with.
104     *
105     * @param keySize the size of the key we want (in bits)
106     * @param ivSize the size of the iv we want (in bits)
107     * @return a ParametersWithIV object.
108     * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
109     */
110    public CipherParameters generateDerivedParameters(
111        int     keySize,
112        int     ivSize)
113    {
114        keySize = keySize / 8;
115        ivSize = ivSize / 8;
116
117        byte[]  dKey = generateDerivedKey(keySize + ivSize);
118
119        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
120    }
121
122    /**
123     * Generate a key parameter for use with a MAC derived from the password,
124     * salt, and iteration count we are currently initialised with.
125     *
126     * @param keySize the size of the key we want (in bits)
127     * @return a KeyParameter object.
128     * @exception IllegalArgumentException if the key length larger than the base hash size.
129     */
130    public CipherParameters generateDerivedMacParameters(
131        int keySize)
132    {
133        return generateDerivedParameters(keySize);
134    }
135}
136