1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.crypto.modes;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.BlockCipher;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.CipherParameters;
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.DataLengthException;
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.params.ParametersWithIV;
7c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.Arrays;
8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/**
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class CBCBlockCipher
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    implements BlockCipher
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[]          IV;
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[]          cbcV;
17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[]          cbcNextV;
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private int             blockSize;
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private BlockCipher     cipher = null;
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private boolean         encrypting;
22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Basic constructor.
25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param cipher the block cipher to be used as the basis of chaining.
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public CBCBlockCipher(
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        BlockCipher cipher)
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.cipher = cipher;
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.blockSize = cipher.getBlockSize();
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.IV = new byte[blockSize];
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.cbcV = new byte[blockSize];
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.cbcNextV = new byte[blockSize];
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the underlying block cipher that we are wrapping.
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the underlying block cipher that we are wrapping.
43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public BlockCipher getUnderlyingCipher()
45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return cipher;
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Initialise the cipher and, possibly, the initialisation vector (IV).
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param encrypting if true the cipher is initialised for
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *  encryption, if false for decryption.
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param params the key and other data required by the cipher.
56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalArgumentException if the params argument is
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * inappropriate.
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void init(
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        boolean             encrypting,
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        CipherParameters    params)
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IllegalArgumentException
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
644c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        boolean oldEncrypting = this.encrypting;
654c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.encrypting = encrypting;
674c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (params instanceof ParametersWithIV)
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
704c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            ParametersWithIV ivParam = (ParametersWithIV)params;
714c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            byte[] iv = ivParam.getIV();
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
734c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (iv.length != blockSize)
744c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
754c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                throw new IllegalArgumentException("initialisation vector must be the same length as block size");
764c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
784c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            System.arraycopy(iv, 0, IV, 0, iv.length);
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
804c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            reset();
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
824c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            // if null it's an IV changed only.
834c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (ivParam.getParameters() != null)
844c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                cipher.init(encrypting, ivParam.getParameters());
864c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
874c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            else if (oldEncrypting != encrypting)
884c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
894c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
904c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
944c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            reset();
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
9670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // if it's null, key is to be reused.
974c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (params != null)
984c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                cipher.init(encrypting, params);
1004c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
1014c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            else if (oldEncrypting != encrypting)
1024c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
1034c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
1044c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the algorithm name and mode.
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the name of the underlying algorithm followed by "/CBC".
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public String getAlgorithmName()
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return cipher.getAlgorithmName() + "/CBC";
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the block size of the underlying cipher.
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the block size of the underlying cipher.
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int getBlockSize()
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return cipher.getBlockSize();
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Process one block of input from the array in and write it to
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * the out array.
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param in the array containing the input data.
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param inOff offset into the in array the data starts at.
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param out the array the output data will be copied into.
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param outOff the offset into the out array the output will start at.
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception DataLengthException if there isn't enough data in in, or
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * space in out.
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalStateException if the cipher isn't initialised.
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes processed and produced.
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int processBlock(
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      in,
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         inOff,
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      out,
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         outOff)
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws DataLengthException, IllegalStateException
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * reset the chaining vector back to the IV and reset the underlying
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * cipher.
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void reset()
156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(IV, 0, cbcV, 0, IV.length);
158c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        Arrays.fill(cbcNextV, (byte)0);
159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        cipher.reset();
161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Do the appropriate chaining step for CBC mode encryption.
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param in the array containing the data to be encrypted.
167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param inOff offset into the in array the data starts at.
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param out the array the encrypted data will be copied into.
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param outOff the offset into the out array the output will start at.
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception DataLengthException if there isn't enough data in in, or
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * space in out.
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalStateException if the cipher isn't initialised.
173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes processed and produced.
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private int encryptBlock(
176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      in,
177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         inOff,
178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      out,
179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         outOff)
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws DataLengthException, IllegalStateException
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if ((inOff + blockSize) > in.length)
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new DataLengthException("input buffer too short");
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
188b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * XOR the cbcV and the input,
189b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * then encrypt the cbcV
190b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
191b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < blockSize; i++)
192b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
193b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            cbcV[i] ^= in[inOff + i];
194b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
195b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
196b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int length = cipher.processBlock(cbcV, 0, out, outOff);
197b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
198b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
199b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * copy ciphertext to cbcV
200b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
201b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
202b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
203b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return length;
204b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
205b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
206b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
207b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Do the appropriate chaining step for CBC mode decryption.
208b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
209b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param in the array containing the data to be decrypted.
210b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param inOff offset into the in array the data starts at.
211b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param out the array the decrypted data will be copied into.
212b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param outOff the offset into the out array the output will start at.
213b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception DataLengthException if there isn't enough data in in, or
214b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * space in out.
215b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalStateException if the cipher isn't initialised.
216b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes processed and produced.
217b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
218b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private int decryptBlock(
219b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      in,
220b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         inOff,
221b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      out,
222b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         outOff)
223b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws DataLengthException, IllegalStateException
224b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
225b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if ((inOff + blockSize) > in.length)
226b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
227b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new DataLengthException("input buffer too short");
228b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
229b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
230b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
231b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
232b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int length = cipher.processBlock(in, inOff, out, outOff);
233b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
234b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
235b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * XOR the cbcV and the output
236b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
237b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < blockSize; i++)
238b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
239b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            out[outOff + i] ^= cbcV[i];
240b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
241b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
242b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        /*
243b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         * swap the back up buffer into next position
244b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam         */
245b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]  tmp;
246b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
247b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        tmp = cbcV;
248b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        cbcV = cbcNextV;
249b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        cbcNextV = tmp;
250b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
251b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return length;
252b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
253b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
254