1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.bouncycastle.crypto.paddings;
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.BlockCipher;
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.BufferedBlockCipher;
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.CipherParameters;
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.DataLengthException;
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.InvalidCipherTextException;
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.ParametersWithRandom;
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * A wrapper class that allows block ciphers to be used to process data in
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a piecemeal fashion with padding. The PaddedBufferedBlockCipher
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * outputs a block only when the buffer is full and more data is being added,
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * or on a doFinal (unless the current block in the buffer is a pad block).
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The default padding mechanism used is the one outlined in PKCS5/PKCS7.
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class PaddedBufferedBlockCipher
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    extends BufferedBlockCipher
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    BlockCipherPadding  padding;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Create a buffered block cipher with the desired padding.
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param cipher the underlying block cipher this buffering object wraps.
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param padding the padding type.
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public PaddedBufferedBlockCipher(
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BlockCipher         cipher,
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BlockCipherPadding  padding)
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.cipher = cipher;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.padding = padding;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        buf = new byte[cipher.getBlockSize()];
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bufOff = 0;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Create a buffered block cipher PKCS7 padding
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param cipher the underlying block cipher this buffering object wraps.
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public PaddedBufferedBlockCipher(
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BlockCipher     cipher)
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this(cipher, new PKCS7Padding());
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * initialise the cipher.
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param forEncryption if true the cipher is initialised for
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  encryption, if false for decryption.
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param params the key and other data required by the cipher.
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalArgumentException if the params argument is
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * inappropriate.
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void init(
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean             forEncryption,
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CipherParameters    params)
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws IllegalArgumentException
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.forEncryption = forEncryption;
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        reset();
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (params instanceof ParametersWithRandom)
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ParametersWithRandom    p = (ParametersWithRandom)params;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            padding.init(p.getRandom());
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cipher.init(forEncryption, p.getParameters());
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            padding.init(null);
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cipher.init(forEncryption, params);
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return the minimum size of the output buffer required for an update
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * plus a doFinal with an input of len bytes.
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param len the length of the input.
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the space required to accommodate a call to update and doFinal
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * with len bytes of input.
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getOutputSize(
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int len)
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int total       = len + bufOff;
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int leftOver    = total % buf.length;
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (leftOver == 0)
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (forEncryption)
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return total + buf.length;
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return total;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return total - leftOver + buf.length;
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return the size of the output buffer required for an update
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * an input of len bytes.
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param len the length of the input.
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the space required to accommodate a call to update
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * with len bytes of input.
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getUpdateOutputSize(
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int len)
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int total       = len + bufOff;
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int leftOver    = total % buf.length;
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (leftOver == 0)
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return total - buf.length;
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return total - leftOver;
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * process a single byte, producing an output block if neccessary.
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param in the input byte.
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out the space for any output that might be produced.
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param outOff the offset from which the output will be copied.
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the number of output bytes copied to out.
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception DataLengthException if there isn't enough space in out.
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalStateException if the cipher isn't initialised.
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int processByte(
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte        in,
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      out,
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         outOff)
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws DataLengthException, IllegalStateException
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         resultLen = 0;
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (bufOff == buf.length)
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            resultLen = cipher.processBlock(buf, 0, out, outOff);
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bufOff = 0;
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        buf[bufOff++] = in;
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return resultLen;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * process an array of bytes, producing output if necessary.
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param in the input byte array.
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param inOff the offset at which the input data starts.
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param len the number of bytes to be copied out of the input array.
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out the space for any output that might be produced.
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param outOff the offset from which the output will be copied.
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the number of output bytes copied to out.
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception DataLengthException if there isn't enough space in out.
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalStateException if the cipher isn't initialised.
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int processBytes(
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      in,
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         inOff,
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         len,
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      out,
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         outOff)
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws DataLengthException, IllegalStateException
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (len < 0)
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("Can't have a negative input length!");
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int blockSize   = getBlockSize();
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length      = getUpdateOutputSize(len);
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (length > 0)
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((outOff + length) > out.length)
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new DataLengthException("output buffer too short");
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int resultLen = 0;
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int gapLen = buf.length - bufOff;
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (len > gapLen)
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.arraycopy(in, inOff, buf, bufOff, gapLen);
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            resultLen += cipher.processBlock(buf, 0, out, outOff);
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bufOff = 0;
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            len -= gapLen;
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            inOff += gapLen;
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            while (len > buf.length)
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                len -= blockSize;
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                inOff += blockSize;
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(in, inOff, buf, bufOff, len);
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bufOff += len;
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return resultLen;
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Process the last block in the buffer. If the buffer is currently
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * full and padding needs to be added a call to doFinal will produce
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * 2 * getBlockSize() bytes.
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out the array the block currently being held is copied into.
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param outOff the offset at which the copying starts.
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the number of output bytes copied to out.
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception DataLengthException if there is insufficient space in out for
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the output or we are decrypting and the input is not block size aligned.
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalStateException if the underlying cipher is not
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * initialised.
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception InvalidCipherTextException if padding is expected and not found.
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int doFinal(
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  out,
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int     outOff)
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws DataLengthException, IllegalStateException, InvalidCipherTextException
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int blockSize = cipher.getBlockSize();
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int resultLen = 0;
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (forEncryption)
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (bufOff == blockSize)
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if ((outOff + 2 * blockSize) > out.length)
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                {
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    reset();
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new DataLengthException("output buffer too short");
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLen = cipher.processBlock(buf, 0, out, outOff);
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bufOff = 0;
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            padding.addPadding(buf, bufOff);
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            reset();
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (bufOff == blockSize)
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLen = cipher.processBlock(buf, 0, buf, 0);
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bufOff = 0;
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                reset();
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new DataLengthException("last block incomplete in decryption");
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLen -= padding.padCount(buf);
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.arraycopy(buf, 0, out, outOff, resultLen);
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            finally
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                reset();
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return resultLen;
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
299