1
package org.bouncycastle.crypto;
5
* A wrapper class that allows block ciphers to be used to process data in
6
* a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
7
* buffer is full and more data is being added, or on a doFinal.
9
* Note: in the case where the underlying cipher is either a CFB cipher or an
10
* OFB one the last block may not be a multiple of the block size.
12
public class BufferedBlockCipher
17
protected boolean forEncryption;
18
protected BlockCipher cipher;
20
protected boolean partialBlockOkay;
21
protected boolean pgpCFB;
24
* constructor for subclasses
26
protected BufferedBlockCipher()
31
* Create a buffered block cipher without padding.
33
* @param cipher the underlying block cipher this buffering object wraps.
35
public BufferedBlockCipher(
40
buf = new byte[cipher.getBlockSize()];
44
// check if we can handle partial blocks on doFinal.
46
String name = cipher.getAlgorithmName();
47
int idx = name.indexOf('/') + 1;
49
pgpCFB = (idx > 0 && name.startsWith("PGP", idx));
53
partialBlockOkay = true;
57
partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
62
* return the cipher this object wraps.
64
* @return the cipher this object wraps.
66
public BlockCipher getUnderlyingCipher()
72
* initialise the cipher.
74
* @param forEncryption if true the cipher is initialised for
75
* encryption, if false for decryption.
76
* @param params the key and other data required by the cipher.
77
* @exception IllegalArgumentException if the params argument is
81
boolean forEncryption,
82
CipherParameters params)
83
throws IllegalArgumentException
85
this.forEncryption = forEncryption;
89
cipher.init(forEncryption, params);
93
* return the blocksize for the underlying cipher.
95
* @return the blocksize for the underlying cipher.
97
public int getBlockSize()
99
return cipher.getBlockSize();
103
* return the size of the output buffer required for an update
104
* an input of len bytes.
106
* @param len the length of the input.
107
* @return the space required to accommodate a call to update
108
* with len bytes of input.
110
public int getUpdateOutputSize(
113
int total = len + bufOff;
118
leftOver = total % buf.length - (cipher.getBlockSize() + 2);
122
leftOver = total % buf.length;
125
return total - leftOver;
129
* return the size of the output buffer required for an update plus a
130
* doFinal with an input of 'length' bytes.
132
* @param length the length of the input.
133
* @return the space required to accommodate a call to update and doFinal
134
* with 'length' bytes of input.
136
public int getOutputSize(
139
// Note: Can assume partialBlockOkay is true for purposes of this calculation
140
return length + bufOff;
144
* process a single byte, producing an output block if neccessary.
146
* @param in the input byte.
147
* @param out the space for any output that might be produced.
148
* @param outOff the offset from which the output will be copied.
149
* @return the number of output bytes copied to out.
150
* @exception DataLengthException if there isn't enough space in out.
151
* @exception IllegalStateException if the cipher isn't initialised.
153
public int processByte(
157
throws DataLengthException, IllegalStateException
163
if (bufOff == buf.length)
165
resultLen = cipher.processBlock(buf, 0, out, outOff);
173
* process an array of bytes, producing output if necessary.
175
* @param in the input byte array.
176
* @param inOff the offset at which the input data starts.
177
* @param len the number of bytes to be copied out of the input array.
178
* @param out the space for any output that might be produced.
179
* @param outOff the offset from which the output will be copied.
180
* @return the number of output bytes copied to out.
181
* @exception DataLengthException if there isn't enough space in out.
182
* @exception IllegalStateException if the cipher isn't initialised.
184
public int processBytes(
190
throws DataLengthException, IllegalStateException
194
throw new IllegalArgumentException("Can't have a negative input length!");
197
int blockSize = getBlockSize();
198
int length = getUpdateOutputSize(len);
202
if ((outOff + length) > out.length)
204
throw new DataLengthException("output buffer too short");
209
int gapLen = buf.length - bufOff;
213
System.arraycopy(in, inOff, buf, bufOff, gapLen);
215
resultLen += cipher.processBlock(buf, 0, out, outOff);
221
while (len > buf.length)
223
resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
230
System.arraycopy(in, inOff, buf, bufOff, len);
234
if (bufOff == buf.length)
236
resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
244
* Process the last block in the buffer.
246
* @param out the array the block currently being held is copied into.
247
* @param outOff the offset at which the copying starts.
248
* @return the number of output bytes copied to out.
249
* @exception DataLengthException if there is insufficient space in out for
250
* the output, or the input is not block size aligned and should be.
251
* @exception IllegalStateException if the underlying cipher is not
253
* @exception InvalidCipherTextException if padding is expected and not found.
254
* @exception DataLengthException if the input is not block size
260
throws DataLengthException, IllegalStateException, InvalidCipherTextException
266
if (outOff + bufOff > out.length)
268
throw new DataLengthException("output buffer too short for doFinal()");
273
if (!partialBlockOkay)
275
throw new DataLengthException("data not block size aligned");
278
cipher.processBlock(buf, 0, buf, 0);
281
System.arraycopy(buf, 0, out, outOff, resultLen);
293
* Reset the buffer and cipher. After resetting the object is in the same
294
* state as it was after the last init (if there was one).
301
for (int i = 0; i < buf.length; i++)
309
// reset the underlying cipher.