1package org.bouncycastle.crypto.generators;
2
3import org.bouncycastle.crypto.CipherParameters;
4import org.bouncycastle.crypto.Digest;
5import org.bouncycastle.crypto.PBEParametersGenerator;
6import org.bouncycastle.crypto.params.KeyParameter;
7import org.bouncycastle.crypto.params.ParametersWithIV;
8
9/**
10 * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 1.
11 * Note this generator is limited to the size of the hash produced by the
12 * digest used to drive it.
13 * <p>
14 * The document this implementation is based on can be found at
15 * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
16 * RSA's PKCS5 Page</a>
17 */
18public class PKCS5S1ParametersGenerator
19    extends PBEParametersGenerator
20{
21    private Digest  digest;
22
23    /**
24     * Construct a PKCS 5 Scheme 1 Parameters generator.
25     *
26     * @param digest the digest to be used as the source of derived keys.
27     */
28    public PKCS5S1ParametersGenerator(
29        Digest  digest)
30    {
31        this.digest = digest;
32    }
33
34    /**
35     * the derived key function, the ith hash of the password and the salt.
36     */
37    private byte[] generateDerivedKey()
38    {
39        byte[] digestBytes = new byte[digest.getDigestSize()];
40
41        digest.update(password, 0, password.length);
42        digest.update(salt, 0, salt.length);
43
44        digest.doFinal(digestBytes, 0);
45        for (int i = 1; i < iterationCount; i++)
46        {
47            digest.update(digestBytes, 0, digestBytes.length);
48            digest.doFinal(digestBytes, 0);
49        }
50
51        return digestBytes;
52    }
53
54    /**
55     * Generate a key parameter derived from the password, salt, and iteration
56     * count we are currently initialised with.
57     *
58     * @param keySize the size of the key we want (in bits)
59     * @return a KeyParameter object.
60     * @exception IllegalArgumentException if the key length larger than the base hash size.
61     */
62    public CipherParameters generateDerivedParameters(
63        int keySize)
64    {
65        keySize = keySize / 8;
66
67        if (keySize > digest.getDigestSize())
68        {
69            throw new IllegalArgumentException(
70                   "Can't generate a derived key " + keySize + " bytes long.");
71        }
72
73        byte[]  dKey = generateDerivedKey();
74
75        return new KeyParameter(dKey, 0, keySize);
76    }
77
78    /**
79     * Generate a key with initialisation vector parameter derived from
80     * the password, salt, and iteration count we are currently initialised
81     * with.
82     *
83     * @param keySize the size of the key we want (in bits)
84     * @param ivSize the size of the iv we want (in bits)
85     * @return a ParametersWithIV object.
86     * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
87     */
88    public CipherParameters generateDerivedParameters(
89        int     keySize,
90        int     ivSize)
91    {
92        keySize = keySize / 8;
93        ivSize = ivSize / 8;
94
95        if ((keySize + ivSize) > digest.getDigestSize())
96        {
97            throw new IllegalArgumentException(
98                   "Can't generate a derived key " + (keySize + ivSize) + " bytes long.");
99        }
100
101        byte[]  dKey = generateDerivedKey();
102
103        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
104    }
105
106    /**
107     * Generate a key parameter for use with a MAC derived from the password,
108     * salt, and iteration count we are currently initialised with.
109     *
110     * @param keySize the size of the key we want (in bits)
111     * @return a KeyParameter object.
112     * @exception IllegalArgumentException if the key length larger than the base hash size.
113     */
114    public CipherParameters generateDerivedMacParameters(
115        int keySize)
116    {
117        return generateDerivedParameters(keySize);
118    }
119}
120