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;
7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/**
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class OFBBlockCipher
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    implements BlockCipher
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[]          IV;
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[]          ofbV;
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private byte[]          ofbOutV;
17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private final int             blockSize;
19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private final BlockCipher     cipher;
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Basic constructor.
23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param cipher the block cipher to be used as the basis of the
25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * feedback mode.
26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param blockSize the block size in bits (note: a multiple of 8)
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public OFBBlockCipher(
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        BlockCipher cipher,
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         blockSize)
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.cipher = cipher;
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.blockSize = blockSize / 8;
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.IV = new byte[cipher.getBlockSize()];
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.ofbV = new byte[cipher.getBlockSize()];
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.ofbOutV = new byte[cipher.getBlockSize()];
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the underlying block cipher that we are wrapping.
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the underlying block cipher that we are wrapping.
44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public BlockCipher getUnderlyingCipher()
46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return cipher;
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Initialise the cipher and, possibly, the initialisation vector (IV).
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * An IV which is too short is handled in FIPS compliant fashion.
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param encrypting if true the cipher is initialised for
56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *  encryption, if false for decryption.
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param params the key and other data required by the cipher.
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalArgumentException if the params argument is
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * inappropriate.
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void init(
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        boolean             encrypting, //ignored by this OFB mode
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        CipherParameters    params)
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IllegalArgumentException
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (params instanceof ParametersWithIV)
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
6870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            ParametersWithIV ivParam = (ParametersWithIV)params;
6970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            byte[]      iv = ivParam.getIV();
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
7170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (iv.length < IV.length)
7270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
7370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                // prepend the supplied IV with zeros (per FIPS PUB 81)
7470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
7570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                for (int i = 0; i < IV.length - iv.length; i++)
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
7770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    IV[i] = 0;
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
7970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
8070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            else
8170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
8270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                System.arraycopy(iv, 0, IV, 0, IV.length);
8370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
8570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            reset();
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
8770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // if null it's an IV changed only.
8870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (ivParam.getParameters() != null)
8970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
9070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                cipher.init(true, ivParam.getParameters());
9170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
9570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            reset();
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
9770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // if it's null, key is to be reused.
9870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (params != null)
9970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                cipher.init(true, params);
10170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the algorithm name and mode.
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the name of the underlying algorithm followed by "/OFB"
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * and the block size in bits
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public String getAlgorithmName()
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8);
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the block size we are operating at (in bytes).
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the block size we are operating at (in bytes).
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int getBlockSize()
123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return blockSize;
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Process one block of input from the array in and write it to
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * the out array.
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param in the array containing the input data.
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param inOff offset into the in array the data starts at.
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param out the array the output data will be copied into.
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param outOff the offset into the out array the output will start at.
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception DataLengthException if there isn't enough data in in, or
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * space in out.
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalStateException if the cipher isn't initialised.
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes processed and produced.
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int processBlock(
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      in,
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         inOff,
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      out,
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         outOff)
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws DataLengthException, IllegalStateException
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if ((inOff + blockSize) > in.length)
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new DataLengthException("input buffer too short");
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if ((outOff + blockSize) > out.length)
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new DataLengthException("output buffer too short");
155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        cipher.processBlock(ofbV, 0, ofbOutV, 0);
158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        //
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        // XOR the ofbV with the plaintext producing the cipher text (and
161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        // the next input block).
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        //
163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < blockSize; i++)
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        //
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        // change over the input block.
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        //
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return blockSize;
175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * reset the feedback vector back to the IV and reset the underlying
179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * cipher.
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void reset()
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        System.arraycopy(IV, 0, ofbV, 0, IV.length);
184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        cipher.reset();
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
188