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