1package org.bouncycastle.crypto.modes; 2 3import org.bouncycastle.crypto.BlockCipher; 4import org.bouncycastle.crypto.BufferedBlockCipher; 5import org.bouncycastle.crypto.DataLengthException; 6import org.bouncycastle.crypto.InvalidCipherTextException; 7 8/** 9 * A wrapper class that allows block ciphers to be used to process data in 10 * a piecemeal fashion with PKCS5/PKCS7 padding. The PaddedBlockCipher 11 * outputs a block only when the buffer is full and more data is being added, 12 * or on a doFinal (unless the current block in the buffer is a pad block). 13 * The padding mechanism used is the one outlined in PKCS5/PKCS7. 14 * 15 * @deprecated use org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher instead. 16 */ 17public class PaddedBlockCipher 18 extends BufferedBlockCipher 19{ 20 /** 21 * Create a buffered block cipher with, or without, padding. 22 * 23 * @param cipher the underlying block cipher this buffering object wraps. 24 */ 25 public PaddedBlockCipher( 26 BlockCipher cipher) 27 { 28 this.cipher = cipher; 29 30 buf = new byte[cipher.getBlockSize()]; 31 bufOff = 0; 32 } 33 34 /** 35 * return the size of the output buffer required for an update plus a 36 * doFinal with an input of len bytes. 37 * 38 * @param len the length of the input. 39 * @return the space required to accommodate a call to update and doFinal 40 * with len bytes of input. 41 */ 42 public int getOutputSize( 43 int len) 44 { 45 int total = len + bufOff; 46 int leftOver = total % buf.length; 47 48 if (leftOver == 0) 49 { 50 if (forEncryption) 51 { 52 return total + buf.length; 53 } 54 55 return total; 56 } 57 58 return total - leftOver + buf.length; 59 } 60 61 /** 62 * return the size of the output buffer required for an update 63 * an input of len bytes. 64 * 65 * @param len the length of the input. 66 * @return the space required to accommodate a call to update 67 * with len bytes of input. 68 */ 69 public int getUpdateOutputSize( 70 int len) 71 { 72 int total = len + bufOff; 73 int leftOver = total % buf.length; 74 75 if (leftOver == 0) 76 { 77 return total - buf.length; 78 } 79 80 return total - leftOver; 81 } 82 83 /** 84 * process a single byte, producing an output block if neccessary. 85 * 86 * @param in the input byte. 87 * @param out the space for any output that might be produced. 88 * @param outOff the offset from which the output will be copied. 89 * @exception DataLengthException if there isn't enough space in out. 90 * @exception IllegalStateException if the cipher isn't initialised. 91 */ 92 public int processByte( 93 byte in, 94 byte[] out, 95 int outOff) 96 throws DataLengthException, IllegalStateException 97 { 98 int resultLen = 0; 99 100 if (bufOff == buf.length) 101 { 102 resultLen = cipher.processBlock(buf, 0, out, outOff); 103 bufOff = 0; 104 } 105 106 buf[bufOff++] = in; 107 108 return resultLen; 109 } 110 111 /** 112 * process an array of bytes, producing output if necessary. 113 * 114 * @param in the input byte array. 115 * @param inOff the offset at which the input data starts. 116 * @param len the number of bytes to be copied out of the input array. 117 * @param out the space for any output that might be produced. 118 * @param outOff the offset from which the output will be copied. 119 * @exception DataLengthException if there isn't enough space in out. 120 * @exception IllegalStateException if the cipher isn't initialised. 121 */ 122 public int processBytes( 123 byte[] in, 124 int inOff, 125 int len, 126 byte[] out, 127 int outOff) 128 throws DataLengthException, IllegalStateException 129 { 130 if (len < 0) 131 { 132 throw new IllegalArgumentException("Can't have a negative input length!"); 133 } 134 135 int blockSize = getBlockSize(); 136 int length = getUpdateOutputSize(len); 137 138 if (length > 0) 139 { 140 if ((outOff + length) > out.length) 141 { 142 throw new DataLengthException("output buffer too short"); 143 } 144 } 145 146 int resultLen = 0; 147 int gapLen = buf.length - bufOff; 148 149 if (len > gapLen) 150 { 151 System.arraycopy(in, inOff, buf, bufOff, gapLen); 152 153 resultLen += cipher.processBlock(buf, 0, out, outOff); 154 155 bufOff = 0; 156 len -= gapLen; 157 inOff += gapLen; 158 159 while (len > buf.length) 160 { 161 resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen); 162 163 len -= blockSize; 164 inOff += blockSize; 165 } 166 } 167 168 System.arraycopy(in, inOff, buf, bufOff, len); 169 170 bufOff += len; 171 172 return resultLen; 173 } 174 175 /** 176 * Process the last block in the buffer. If the buffer is currently 177 * full and padding needs to be added a call to doFinal will produce 178 * 2 * getBlockSize() bytes. 179 * 180 * @param out the array the block currently being held is copied into. 181 * @param outOff the offset at which the copying starts. 182 * @exception DataLengthException if there is insufficient space in out for 183 * the output or we are decrypting and the input is not block size aligned. 184 * @exception IllegalStateException if the underlying cipher is not 185 * initialised. 186 * @exception InvalidCipherTextException if padding is expected and not found. 187 */ 188 public int doFinal( 189 byte[] out, 190 int outOff) 191 throws DataLengthException, IllegalStateException, InvalidCipherTextException 192 { 193 int blockSize = cipher.getBlockSize(); 194 int resultLen = 0; 195 196 if (forEncryption) 197 { 198 if (bufOff == blockSize) 199 { 200 if ((outOff + 2 * blockSize) > out.length) 201 { 202 throw new DataLengthException("output buffer too short"); 203 } 204 205 resultLen = cipher.processBlock(buf, 0, out, outOff); 206 bufOff = 0; 207 } 208 209 // 210 // add PKCS7 padding 211 // 212 byte code = (byte)(blockSize - bufOff); 213 214 while (bufOff < blockSize) 215 { 216 buf[bufOff] = code; 217 bufOff++; 218 } 219 220 resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen); 221 } 222 else 223 { 224 if (bufOff == blockSize) 225 { 226 resultLen = cipher.processBlock(buf, 0, buf, 0); 227 bufOff = 0; 228 } 229 else 230 { 231 throw new DataLengthException("last block incomplete in decryption"); 232 } 233 234 // 235 // remove PKCS7 padding 236 // 237 int count = buf[blockSize - 1] & 0xff; 238 239 if ((count < 0) || (count > blockSize)) 240 { 241 throw new InvalidCipherTextException("pad block corrupted"); 242 } 243 244 resultLen -= count; 245 246 System.arraycopy(buf, 0, out, outOff, resultLen); 247 } 248 249 reset(); 250 251 return resultLen; 252 } 253} 254