CTSBlockCipher.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.orgpackage org.bouncycastle.crypto.modes; 2ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 3ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.orgimport org.bouncycastle.crypto.BlockCipher; 4ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.orgimport org.bouncycastle.crypto.BufferedBlockCipher; 5ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.orgimport org.bouncycastle.crypto.DataLengthException; 6ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.orgimport org.bouncycastle.crypto.InvalidCipherTextException; 7ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 8ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org/** 9ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to 10ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * be used to produce cipher text which is the same length as the plain text. 11ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org */ 12ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.orgpublic class CTSBlockCipher 13ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org extends BufferedBlockCipher 14ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org{ 15ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org private int blockSize; 16ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 17ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org /** 18ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * Create a buffered block cipher that uses Cipher Text Stealing 19ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * 20ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param cipher the underlying block cipher this buffering object wraps. 21ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org */ 22ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org public CTSBlockCipher( 23ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org BlockCipher cipher) 24d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org { 25d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher) || (cipher instanceof SICBlockCipher)) 26d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org { 27d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org // TODO: This is broken - need to introduce marker interface to differentiate block cipher primitive from mode? 28d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers"); 29d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org } 30ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 31d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org this.cipher = cipher; 32d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org 33d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org blockSize = cipher.getBlockSize(); 34d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org 35d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org buf = new byte[blockSize * 2]; 36d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org bufOff = 0; 37d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org } 38d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org 39d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org /** 40d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * return the size of the output buffer required for an update 41d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * an input of len bytes. 42d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * 43ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param len the length of the input. 44d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * @return the space required to accommodate a call to update 45d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * with len bytes of input. 46ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org */ 47d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org public int getUpdateOutputSize( 48d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org int len) 49d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org { 50d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org int total = len + bufOff; 51d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org int leftOver = total % buf.length; 52d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org 53ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (leftOver == 0) 54ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 55ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org return total - buf.length; 5641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org } 5741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org 58ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org return total - leftOver; 59ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org } 6041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org 6141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org /** 6241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * return the size of the output buffer required for an update plus a 6341294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * doFinal with an input of len bytes. 6441294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * 6541294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * @param len the length of the input. 6641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * @return the space required to accommodate a call to update and doFinal 67ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * with len bytes of input. 6841294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org */ 69ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org public int getOutputSize( 7041294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org int len) 71ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org { 72e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org return len + bufOff; 73e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org } 74ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 75ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org /** 76ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * process a single byte, producing an output block if necessary. 7741294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * 78ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * @param in the input byte. 79ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * @param out the space for any output that might be produced. 80ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * @param outOff the offset from which the output will be copied. 81ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * @return the number of output bytes copied to out. 8241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org * @exception DataLengthException if there isn't enough space in out. 83ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * @exception IllegalStateException if the cipher isn't initialised. 84ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org */ 85ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org public int processByte( 86ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org byte in, 87ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org byte[] out, 88ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org int outOff) 89ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org throws DataLengthException, IllegalStateException 90ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org { 9141294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org int resultLen = 0; 9241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org 93ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org if (bufOff == buf.length) 94ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org { 95ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org resultLen = cipher.processBlock(buf, 0, out, outOff); 96ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org System.arraycopy(buf, blockSize, buf, 0, blockSize); 97ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 98ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org bufOff = blockSize; 99ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org } 100ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 101ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org buf[bufOff++] = in; 102ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 103ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org return resultLen; 104ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 105ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 106ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org /** 107ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * process an array of bytes, producing output if necessary. 108ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * 109ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param in the input byte array. 110ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param inOff the offset at which the input data starts. 111ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param len the number of bytes to be copied out of the input array. 112ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param out the space for any output that might be produced. 113ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param outOff the offset from which the output will be copied. 114ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @return the number of output bytes copied to out. 115ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @exception DataLengthException if there isn't enough space in out. 116ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @exception IllegalStateException if the cipher isn't initialised. 117ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org */ 118ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org public int processBytes( 119ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org byte[] in, 120ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int inOff, 121ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int len, 122ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org byte[] out, 123ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int outOff) 124ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org throws DataLengthException, IllegalStateException 125ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 126ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (len < 0) 127ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 128ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org throw new IllegalArgumentException("Can't have a negative input length!"); 129ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 130ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 131ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int blockSize = getBlockSize(); 132ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int length = getUpdateOutputSize(len); 133ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 134ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (length > 0) 135ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 136ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if ((outOff + length) > out.length) 137ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 138ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org throw new DataLengthException("output buffer too short"); 139ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 140ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 141ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 142ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int resultLen = 0; 143ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int gapLen = buf.length - bufOff; 144ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 145ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (len > gapLen) 146ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 147ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(in, inOff, buf, bufOff, gapLen); 148ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 149ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org resultLen += cipher.processBlock(buf, 0, out, outOff); 150ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(buf, blockSize, buf, 0, blockSize); 151ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 152ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org bufOff = blockSize; 153ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 154ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org len -= gapLen; 155ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org inOff += gapLen; 156ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 157ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org while (len > blockSize) 158ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 159ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(in, inOff, buf, bufOff, blockSize); 160ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen); 161ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(buf, blockSize, buf, 0, blockSize); 162ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 163ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org len -= blockSize; 164ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org inOff += blockSize; 165ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 166ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 167ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 168ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(in, inOff, buf, bufOff, len); 169ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 170ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org bufOff += len; 171ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 172ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org return resultLen; 173ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org } 174ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 175ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org /** 176ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * Process the last block in the buffer. 177ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * 178ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @param out the array the block currently being held is copied into. 17910a9a0d835561a7f2300c561c514efcf374554d6fgalligan@chromium.org * @param outOff the offset at which the copying starts. 180ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @return the number of output bytes copied to out. 181ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @exception DataLengthException if there is insufficient space in out for 182ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * the output. 183ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @exception IllegalStateException if the underlying cipher is not 184ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * initialised. 185ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org * @exception InvalidCipherTextException if cipher text decrypts wrongly (in 186ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org * case the exception will never get thrown). 187ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org */ 188ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org public int doFinal( 189ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org byte[] out, 190ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int outOff) 191ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org throws DataLengthException, IllegalStateException, InvalidCipherTextException 192ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 193ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (bufOff + outOff > out.length) 194ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 195ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org throw new DataLengthException("output buffer to small in doFinal"); 196ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 197ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 198ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int blockSize = cipher.getBlockSize(); 199ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org int len = bufOff - blockSize; 200ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org byte[] block = new byte[blockSize]; 201ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 202ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (forEncryption) 203ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 204ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (bufOff < blockSize) 205ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 206ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org throw new DataLengthException("need at least one block of input for CTS"); 207ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 208ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 209ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org cipher.processBlock(buf, 0, block, 0); 210ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 211ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (bufOff > blockSize) 212ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 213ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org for (int i = bufOff; i != buf.length; i++) 214ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org { 215ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org buf[i] = block[i - blockSize]; 216ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org } 217ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org 218ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org for (int i = blockSize; i != bufOff; i++) 219ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org { 220ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org buf[i] ^= block[i - blockSize]; 221ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 222ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 223ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (cipher instanceof CBCBlockCipher) 224ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 225ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); 226ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 227ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org c.processBlock(buf, blockSize, out, outOff); 228ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 229ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org else 230ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 231ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org cipher.processBlock(buf, blockSize, out, outOff); 232ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 233ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 234ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(block, 0, out, outOff + blockSize, len); 235ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 236ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org else 237ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 238ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org System.arraycopy(block, 0, out, outOff, blockSize); 239ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 240ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 241ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org else 242ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 243411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org if (bufOff < blockSize) 244ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org { 245411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org throw new DataLengthException("need at least one block of input for CTS"); 246ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org } 247ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 248ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org byte[] lastBlock = new byte[blockSize]; 249ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org 250ed759d81a39febed3a8a395386639d54307504aagrunell@chromium.org if (bufOff > blockSize) 251 { 252 if (cipher instanceof CBCBlockCipher) 253 { 254 BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); 255 256 c.processBlock(buf, 0, block, 0); 257 } 258 else 259 { 260 cipher.processBlock(buf, 0, block, 0); 261 } 262 263 for (int i = blockSize; i != bufOff; i++) 264 { 265 lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]); 266 } 267 268 System.arraycopy(buf, blockSize, block, 0, len); 269 270 cipher.processBlock(block, 0, out, outOff); 271 System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); 272 } 273 else 274 { 275 cipher.processBlock(buf, 0, block, 0); 276 277 System.arraycopy(block, 0, out, outOff, blockSize); 278 } 279 } 280 281 int offset = bufOff; 282 283 reset(); 284 285 return offset; 286 } 287} 288