PKCS12ParametersGenerator.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.crypto.generators;
2
3import org.bouncycastle.crypto.CipherParameters;
4import org.bouncycastle.crypto.Digest;
5import org.bouncycastle.crypto.ExtendedDigest;
6import org.bouncycastle.crypto.PBEParametersGenerator;
7import org.bouncycastle.crypto.params.KeyParameter;
8import org.bouncycastle.crypto.params.ParametersWithIV;
9
10/**
11 * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
12 * <p>
13 * The document this implementation is based on can be found at
14 * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
15 * RSA's PKCS12 Page</a>
16 */
17public class PKCS12ParametersGenerator
18    extends PBEParametersGenerator
19{
20    public static final int KEY_MATERIAL = 1;
21    public static final int IV_MATERIAL  = 2;
22    public static final int MAC_MATERIAL = 3;
23
24    private Digest digest;
25
26    private int     u;
27    private int     v;
28
29    /**
30     * Construct a PKCS 12 Parameters generator. This constructor will
31     * accept any digest which also implements ExtendedDigest.
32     *
33     * @param digest the digest to be used as the source of derived keys.
34     * @exception IllegalArgumentException if an unknown digest is passed in.
35     */
36    public PKCS12ParametersGenerator(
37        Digest  digest)
38    {
39        this.digest = digest;
40        if (digest instanceof ExtendedDigest)
41        {
42            u = digest.getDigestSize();
43            v = ((ExtendedDigest)digest).getByteLength();
44        }
45        else
46        {
47            throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
48        }
49    }
50
51    /**
52     * add a + b + 1, returning the result in a. The a value is treated
53     * as a BigInteger of length (b.length * 8) bits. The result is
54     * modulo 2^b.length in case of overflow.
55     */
56    private void adjust(
57        byte[]  a,
58        int     aOff,
59        byte[]  b)
60    {
61        int  x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
62
63        a[aOff + b.length - 1] = (byte)x;
64        x >>>= 8;
65
66        for (int i = b.length - 2; i >= 0; i--)
67        {
68            x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
69            a[aOff + i] = (byte)x;
70            x >>>= 8;
71        }
72    }
73
74    /**
75     * generation of a derived key ala PKCS12 V1.0.
76     */
77    private byte[] generateDerivedKey(
78        int idByte,
79        int n)
80    {
81        byte[]  D = new byte[v];
82        byte[]  dKey = new byte[n];
83
84        for (int i = 0; i != D.length; i++)
85        {
86            D[i] = (byte)idByte;
87        }
88
89        byte[]  S;
90
91        if ((salt != null) && (salt.length != 0))
92        {
93            S = new byte[v * ((salt.length + v - 1) / v)];
94
95            for (int i = 0; i != S.length; i++)
96            {
97                S[i] = salt[i % salt.length];
98            }
99        }
100        else
101        {
102            S = new byte[0];
103        }
104
105        byte[]  P;
106
107        if ((password != null) && (password.length != 0))
108        {
109            P = new byte[v * ((password.length + v - 1) / v)];
110
111            for (int i = 0; i != P.length; i++)
112            {
113                P[i] = password[i % password.length];
114            }
115        }
116        else
117        {
118            P = new byte[0];
119        }
120
121        byte[]  I = new byte[S.length + P.length];
122
123        System.arraycopy(S, 0, I, 0, S.length);
124        System.arraycopy(P, 0, I, S.length, P.length);
125
126        byte[]  B = new byte[v];
127        int     c = (n + u - 1) / u;
128
129        for (int i = 1; i <= c; i++)
130        {
131            byte[]  A = new byte[u];
132
133            digest.update(D, 0, D.length);
134            digest.update(I, 0, I.length);
135            digest.doFinal(A, 0);
136            for (int j = 1; j < iterationCount; j++)
137            {
138                digest.update(A, 0, A.length);
139                digest.doFinal(A, 0);
140            }
141
142            for (int j = 0; j != B.length; j++)
143            {
144                B[j] = A[j % A.length];
145            }
146
147            for (int j = 0; j != I.length / v; j++)
148            {
149                adjust(I, j * v, B);
150            }
151
152            if (i == c)
153            {
154                System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
155            }
156            else
157            {
158                System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
159            }
160        }
161
162        return dKey;
163    }
164
165    /**
166     * Generate a key parameter derived from the password, salt, and iteration
167     * count we are currently initialised with.
168     *
169     * @param keySize the size of the key we want (in bits)
170     * @return a KeyParameter object.
171     */
172    public CipherParameters generateDerivedParameters(
173        int keySize)
174    {
175        keySize = keySize / 8;
176
177        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
178
179        return new KeyParameter(dKey, 0, keySize);
180    }
181
182    /**
183     * Generate a key with initialisation vector parameter derived from
184     * the password, salt, and iteration count we are currently initialised
185     * with.
186     *
187     * @param keySize the size of the key we want (in bits)
188     * @param ivSize the size of the iv we want (in bits)
189     * @return a ParametersWithIV object.
190     */
191    public CipherParameters generateDerivedParameters(
192        int     keySize,
193        int     ivSize)
194    {
195        keySize = keySize / 8;
196        ivSize = ivSize / 8;
197
198        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
199
200        byte[]  iv = generateDerivedKey(IV_MATERIAL, ivSize);
201
202        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
203    }
204
205    /**
206     * Generate a key parameter for use with a MAC derived from the password,
207     * salt, and iteration count we are currently initialised with.
208     *
209     * @param keySize the size of the key we want (in bits)
210     * @return a KeyParameter object.
211     */
212    public CipherParameters generateDerivedMacParameters(
213        int keySize)
214    {
215        keySize = keySize / 8;
216
217        byte[]  dKey = generateDerivedKey(MAC_MATERIAL, keySize);
218
219        return new KeyParameter(dKey, 0, keySize);
220    }
221}
222