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