PKCS5S2ParametersGenerator.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)package org.bouncycastle.crypto.generators;
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.CipherParameters;
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.Digest;
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.Mac;
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.PBEParametersGenerator;
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// BEGIN android-changed
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.digests.AndroidDigestFactory;
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// END android-changed
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.macs.HMac;
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.params.KeyParameter;
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import org.bouncycastle.crypto.params.ParametersWithIV;
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This generator uses a SHA-1 HMac as the calculation function.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * <p>
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * The document this implementation is based on can be found at
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * RSA's PKCS5 Page</a>
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)public class PKCS5S2ParametersGenerator
2353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    extends PBEParametersGenerator
2409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
2553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    private Mac hMac;
26a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
28c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)     * construct a PKCS5 Scheme 2 Parameters generator.
2902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch     */
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    public PKCS5S2ParametersGenerator()
317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    {
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // BEGIN android-changed
335d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    	this(AndroidDigestFactory.getSHA1());
3402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        // END android-changed
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    public PKCS5S2ParametersGenerator(Digest digest)
3809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    {
3909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        hMac = new HMac(digest);
4009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
4109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
4209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    private void F(
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        byte[]  P,
4451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        byte[]  S,
4502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        int     c,
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        byte[]  iBuf,
47926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        byte[]  out,
4809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        int     outOff)
4909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    {
5002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        byte[]              state = new byte[hMac.getMacSize()];
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        CipherParameters    param = new KeyParameter(P);
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        hMac.init(param);
5409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
5509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (S != null)
5609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        {
5709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            hMac.update(S, 0, S.length);
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
60c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        hMac.update(iBuf, 0, iBuf.length);
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        hMac.doFinal(state, 0);
63
64        System.arraycopy(state, 0, out, outOff, state.length);
65
66        if (c == 0)
67        {
68            throw new IllegalArgumentException("iteration count must be at least 1.");
69        }
70
71        for (int count = 1; count < c; count++)
72        {
73            hMac.init(param);
74            hMac.update(state, 0, state.length);
75            hMac.doFinal(state, 0);
76
77            for (int j = 0; j != state.length; j++)
78            {
79                out[outOff + j] ^= state[j];
80            }
81        }
82    }
83
84    private void intToOctet(
85        byte[]  buf,
86        int     i)
87    {
88        buf[0] = (byte)(i >>> 24);
89        buf[1] = (byte)(i >>> 16);
90        buf[2] = (byte)(i >>> 8);
91        buf[3] = (byte)i;
92    }
93
94    private byte[] generateDerivedKey(
95        int dkLen)
96    {
97        int     hLen = hMac.getMacSize();
98        int     l = (dkLen + hLen - 1) / hLen;
99        byte[]  iBuf = new byte[4];
100        byte[]  out = new byte[l * hLen];
101
102        for (int i = 1; i <= l; i++)
103        {
104            intToOctet(iBuf, i);
105
106            F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
107        }
108
109        return out;
110    }
111
112    /**
113     * Generate a key parameter derived from the password, salt, and iteration
114     * count we are currently initialised with.
115     *
116     * @param keySize the size of the key we want (in bits)
117     * @return a KeyParameter object.
118     */
119    public CipherParameters generateDerivedParameters(
120        int keySize)
121    {
122        keySize = keySize / 8;
123
124        byte[]  dKey = generateDerivedKey(keySize);
125
126        return new KeyParameter(dKey, 0, keySize);
127    }
128
129    /**
130     * Generate a key with initialisation vector parameter derived from
131     * the password, salt, and iteration count we are currently initialised
132     * with.
133     *
134     * @param keySize the size of the key we want (in bits)
135     * @param ivSize the size of the iv we want (in bits)
136     * @return a ParametersWithIV object.
137     */
138    public CipherParameters generateDerivedParameters(
139        int     keySize,
140        int     ivSize)
141    {
142        keySize = keySize / 8;
143        ivSize = ivSize / 8;
144
145        byte[]  dKey = generateDerivedKey(keySize + ivSize);
146
147        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
148    }
149
150    /**
151     * Generate a key parameter for use with a MAC derived from the password,
152     * salt, and iteration count we are currently initialised with.
153     *
154     * @param keySize the size of the key we want (in bits)
155     * @return a KeyParameter object.
156     */
157    public CipherParameters generateDerivedMacParameters(
158        int keySize)
159    {
160        return generateDerivedParameters(keySize);
161    }
162}
163