001: package org.bouncycastle.crypto.modes;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.BufferedBlockCipher;
005: import org.bouncycastle.crypto.DataLengthException;
006: import org.bouncycastle.crypto.InvalidCipherTextException;
007:
008: /**
009: * A wrapper class that allows block ciphers to be used to process data in
010: * a piecemeal fashion with PKCS5/PKCS7 padding. The PaddedBlockCipher
011: * outputs a block only when the buffer is full and more data is being added,
012: * or on a doFinal (unless the current block in the buffer is a pad block).
013: * The padding mechanism used is the one outlined in PKCS5/PKCS7.
014: *
015: * @deprecated use org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher instead.
016: */
017: public class PaddedBlockCipher extends BufferedBlockCipher {
018: /**
019: * Create a buffered block cipher with, or without, padding.
020: *
021: * @param cipher the underlying block cipher this buffering object wraps.
022: */
023: public PaddedBlockCipher(BlockCipher cipher) {
024: this .cipher = cipher;
025:
026: buf = new byte[cipher.getBlockSize()];
027: bufOff = 0;
028: }
029:
030: /**
031: * return the size of the output buffer required for an update plus a
032: * doFinal with an input of len bytes.
033: *
034: * @param len the length of the input.
035: * @return the space required to accommodate a call to update and doFinal
036: * with len bytes of input.
037: */
038: public int getOutputSize(int len) {
039: int total = len + bufOff;
040: int leftOver = total % buf.length;
041:
042: if (leftOver == 0) {
043: if (forEncryption) {
044: return total + buf.length;
045: }
046:
047: return total;
048: }
049:
050: return total - leftOver + buf.length;
051: }
052:
053: /**
054: * return the size of the output buffer required for an update
055: * an input of len bytes.
056: *
057: * @param len the length of the input.
058: * @return the space required to accommodate a call to update
059: * with len bytes of input.
060: */
061: public int getUpdateOutputSize(int len) {
062: int total = len + bufOff;
063: int leftOver = total % buf.length;
064:
065: if (leftOver == 0) {
066: return total - buf.length;
067: }
068:
069: return total - leftOver;
070: }
071:
072: /**
073: * process a single byte, producing an output block if neccessary.
074: *
075: * @param in the input byte.
076: * @param out the space for any output that might be produced.
077: * @param outOff the offset from which the output will be copied.
078: * @exception DataLengthException if there isn't enough space in out.
079: * @exception IllegalStateException if the cipher isn't initialised.
080: */
081: public int processByte(byte in, byte[] out, int outOff)
082: throws DataLengthException, IllegalStateException {
083: int resultLen = 0;
084:
085: if (bufOff == buf.length) {
086: resultLen = cipher.processBlock(buf, 0, out, outOff);
087: bufOff = 0;
088: }
089:
090: buf[bufOff++] = in;
091:
092: return resultLen;
093: }
094:
095: /**
096: * process an array of bytes, producing output if necessary.
097: *
098: * @param in the input byte array.
099: * @param inOff the offset at which the input data starts.
100: * @param len the number of bytes to be copied out of the input array.
101: * @param out the space for any output that might be produced.
102: * @param outOff the offset from which the output will be copied.
103: * @exception DataLengthException if there isn't enough space in out.
104: * @exception IllegalStateException if the cipher isn't initialised.
105: */
106: public int processBytes(byte[] in, int inOff, int len, byte[] out,
107: int outOff) throws DataLengthException,
108: IllegalStateException {
109: if (len < 0) {
110: throw new IllegalArgumentException(
111: "Can't have a negative input length!");
112: }
113:
114: int blockSize = getBlockSize();
115: int length = getUpdateOutputSize(len);
116:
117: if (length > 0) {
118: if ((outOff + length) > out.length) {
119: throw new DataLengthException("output buffer too short");
120: }
121: }
122:
123: int resultLen = 0;
124: int gapLen = buf.length - bufOff;
125:
126: if (len > gapLen) {
127: System.arraycopy(in, inOff, buf, bufOff, gapLen);
128:
129: resultLen += cipher.processBlock(buf, 0, out, outOff);
130:
131: bufOff = 0;
132: len -= gapLen;
133: inOff += gapLen;
134:
135: while (len > buf.length) {
136: resultLen += cipher.processBlock(in, inOff, out, outOff
137: + resultLen);
138:
139: len -= blockSize;
140: inOff += blockSize;
141: }
142: }
143:
144: System.arraycopy(in, inOff, buf, bufOff, len);
145:
146: bufOff += len;
147:
148: return resultLen;
149: }
150:
151: /**
152: * Process the last block in the buffer. If the buffer is currently
153: * full and padding needs to be added a call to doFinal will produce
154: * 2 * getBlockSize() bytes.
155: *
156: * @param out the array the block currently being held is copied into.
157: * @param outOff the offset at which the copying starts.
158: * @exception DataLengthException if there is insufficient space in out for
159: * the output or we are decrypting and the input is not block size aligned.
160: * @exception IllegalStateException if the underlying cipher is not
161: * initialised.
162: * @exception InvalidCipherTextException if padding is expected and not found.
163: */
164: public int doFinal(byte[] out, int outOff)
165: throws DataLengthException, IllegalStateException,
166: InvalidCipherTextException {
167: int blockSize = cipher.getBlockSize();
168: int resultLen = 0;
169:
170: if (forEncryption) {
171: if (bufOff == blockSize) {
172: if ((outOff + 2 * blockSize) > out.length) {
173: throw new DataLengthException(
174: "output buffer too short");
175: }
176:
177: resultLen = cipher.processBlock(buf, 0, out, outOff);
178: bufOff = 0;
179: }
180:
181: //
182: // add PKCS7 padding
183: //
184: byte code = (byte) (blockSize - bufOff);
185:
186: while (bufOff < blockSize) {
187: buf[bufOff] = code;
188: bufOff++;
189: }
190:
191: resultLen += cipher.processBlock(buf, 0, out, outOff
192: + resultLen);
193: } else {
194: if (bufOff == blockSize) {
195: resultLen = cipher.processBlock(buf, 0, buf, 0);
196: bufOff = 0;
197: } else {
198: throw new DataLengthException(
199: "last block incomplete in decryption");
200: }
201:
202: //
203: // remove PKCS7 padding
204: //
205: int count = buf[blockSize - 1] & 0xff;
206:
207: if ((count < 0) || (count > blockSize)) {
208: throw new InvalidCipherTextException(
209: "pad block corrupted");
210: }
211:
212: resultLen -= count;
213:
214: System.arraycopy(buf, 0, out, outOff, resultLen);
215: }
216:
217: reset();
218:
219: return resultLen;
220: }
221: }
|