1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.bouncycastle.crypto.modes;
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.BlockCipher;
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.CipherParameters;
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.DataLengthException;
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.ParametersWithIV;
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class CFBBlockCipher
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    implements BlockCipher
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[]          IV;
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[]          cfbV;
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[]          cfbOutV;
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int             blockSize;
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private BlockCipher     cipher = null;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean         encrypting;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Basic constructor.
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param cipher the block cipher to be used as the basis of the
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * feedback mode.
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param bitBlockSize the block size in bits (note: a multiple of 8)
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public CFBBlockCipher(
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BlockCipher cipher,
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         bitBlockSize)
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.cipher = cipher;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.blockSize = bitBlockSize / 8;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.IV = new byte[cipher.getBlockSize()];
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.cfbV = new byte[cipher.getBlockSize()];
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.cfbOutV = new byte[cipher.getBlockSize()];
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return the underlying block cipher that we are wrapping.
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the underlying block cipher that we are wrapping.
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public BlockCipher getUnderlyingCipher()
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return cipher;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Initialise the cipher and, possibly, the initialisation vector (IV).
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * An IV which is too short is handled in FIPS compliant fashion.
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param encrypting if true the cipher is initialised for
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  encryption, if false for decryption.
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param params the key and other data required by the cipher.
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalArgumentException if the params argument is
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * inappropriate.
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void init(
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean             encrypting,
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CipherParameters    params)
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws IllegalArgumentException
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.encrypting = encrypting;
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (params instanceof ParametersWithIV)
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ParametersWithIV ivParam = (ParametersWithIV)params;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                byte[]      iv = ivParam.getIV();
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (iv.length < IV.length)
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                {
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // prepend the supplied IV with zeros (per FIPS PUB 81)
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    for (int i = 0; i < IV.length - iv.length; i++)
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    {
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        IV[i] = 0;
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                else
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                {
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.arraycopy(iv, 0, IV, 0, IV.length);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                reset();
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                cipher.init(true, ivParam.getParameters());
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                reset();
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                cipher.init(true, params);
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return the algorithm name and mode.
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the name of the underlying algorithm followed by "/CFB"
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * and the block size in bits.
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String getAlgorithmName()
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return the block size we are operating at.
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the block size we are operating at (in bytes).
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getBlockSize()
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return blockSize;
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Process one block of input from the array in and write it to
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the out array.
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param in the array containing the input data.
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param inOff offset into the in array the data starts at.
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out the array the output data will be copied into.
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param outOff the offset into the out array the output will start at.
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception DataLengthException if there isn't enough data in in, or
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * space in out.
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalStateException if the cipher isn't initialised.
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the number of bytes processed and produced.
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int processBlock(
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      in,
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         inOff,
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      out,
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         outOff)
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws DataLengthException, IllegalStateException
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Do the appropriate processing for CFB mode encryption.
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param in the array containing the data to be encrypted.
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param inOff offset into the in array the data starts at.
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out the array the encrypted data will be copied into.
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param outOff the offset into the out array the output will start at.
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception DataLengthException if there isn't enough data in in, or
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * space in out.
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalStateException if the cipher isn't initialised.
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the number of bytes processed and produced.
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int encryptBlock(
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      in,
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         inOff,
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      out,
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         outOff)
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws DataLengthException, IllegalStateException
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((inOff + blockSize) > in.length)
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new DataLengthException("input buffer too short");
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((outOff + blockSize) > out.length)
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new DataLengthException("output buffer too short");
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cipher.processBlock(cfbV, 0, cfbOutV, 0);
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // XOR the cfbV with the plaintext producing the cipher text
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < blockSize; i++)
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // change over the input block.
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize);
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return blockSize;
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Do the appropriate processing for CFB mode decryption.
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param in the array containing the data to be decrypted.
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param inOff offset into the in array the data starts at.
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out the array the encrypted data will be copied into.
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param outOff the offset into the out array the output will start at.
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception DataLengthException if there isn't enough data in in, or
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * space in out.
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @exception IllegalStateException if the cipher isn't initialised.
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the number of bytes processed and produced.
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int decryptBlock(
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      in,
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         inOff,
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]      out,
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int         outOff)
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws DataLengthException, IllegalStateException
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((inOff + blockSize) > in.length)
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new DataLengthException("input buffer too short");
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((outOff + blockSize) > out.length)
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new DataLengthException("output buffer too short");
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cipher.processBlock(cfbV, 0, cfbOutV, 0);
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // change over the input block.
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(in, inOff, cfbV, cfbV.length - blockSize, blockSize);
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // XOR the cfbV with the plaintext producing the plain text
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < blockSize; i++)
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return blockSize;
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * reset the chaining vector back to the IV and reset the underlying
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * cipher.
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void reset()
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(IV, 0, cfbV, 0, IV.length);
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cipher.reset();
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
251