Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java
41161 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.crypto.provider;2627import javax.crypto.IllegalBlockSizeException;28import javax.crypto.ShortBufferException;2930/**31* This class represents ciphers in cipher text stealing (CTS) mode.32* <br>CTS provides a way to allow block ciphers to operate on partial33* blocks without padding, and all bits of the message go through34* the encryption algorithm, rather than simply being XOR'd.35* <br>More details can be found in RFC 2040 section 8 "Description36* of RC5-CTS".37*38* <p>This mode is implemented independently of a particular cipher.39* Ciphers to which this mode should apply (e.g., DES) must be40* <i>plugged-in</i> using the constructor.41*42* <p>NOTE#1: CTS requires the input data to be at least one block43* long. Thus, callers of this class has to buffer the input data44* to make sure the input data passed to encryptFinal()/decryptFinal()45* is not shorter than a block.46* <p>NOTE#2: This class does not deal with buffering or padding47* just like all other cipher mode implementations.48*49* @author Valerie Peng50*/5152final class CipherTextStealing extends CipherBlockChaining {5354CipherTextStealing(SymmetricCipher embeddedCipher) {55super(embeddedCipher);56}5758/**59* Gets the name of this feedback mode.60*61* @return the string <code>CBC</code>62*/63String getFeedback() {64return "CTS";65}6667/**68* Performs the last encryption operation.69*70* <p>The input plain text <code>plain</code>, starting at71* <code>plainOffset</code> and ending at72* <code>(plainOffset + len - 1)</code>, is encrypted.73* The result is stored in <code>cipher</code>, starting at74* <code>cipherOffset</code>.75*76* <p>It is the application's responsibility to make sure that77* <code>plainLen</code> is a multiple of the embedded cipher's block size,78* as any excess bytes are ignored.79*80* @param plain the buffer with the input data to be encrypted81* @param plainOffset the offset in <code>plain</code>82* @param plainLen the length of the input data83* @param cipher the buffer for the result84* @param cipherOffset the offset in <code>cipher</code>85* @return the number of bytes placed into <code>cipher</code>86*/87int encryptFinal(byte[] plain, int plainOffset, int plainLen,88byte[] cipher, int cipherOffset)89throws IllegalBlockSizeException {9091if (plainLen < blockSize) {92throw new IllegalBlockSizeException("input is too short!");93} else if (plainLen == blockSize) {94encrypt(plain, plainOffset, plainLen, cipher, cipherOffset);95} else {96// number of bytes in the last block97int nLeft = plainLen % blockSize;98if (nLeft == 0) {99encrypt(plain, plainOffset, plainLen, cipher, cipherOffset);100// swap the last two blocks after encryption101int lastBlkIndex = cipherOffset + plainLen - blockSize;102int nextToLastBlkIndex = lastBlkIndex - blockSize;103byte[] tmp = new byte[blockSize];104System.arraycopy(cipher, lastBlkIndex, tmp, 0, blockSize);105System.arraycopy(cipher, nextToLastBlkIndex,106cipher, lastBlkIndex, blockSize);107System.arraycopy(tmp, 0, cipher, nextToLastBlkIndex,108blockSize);109} else {110int newPlainLen = plainLen - (blockSize + nLeft);111if (newPlainLen > 0) {112encrypt(plain, plainOffset, newPlainLen, cipher,113cipherOffset);114plainOffset += newPlainLen;115cipherOffset += newPlainLen;116}117118// Do final CTS step for last two blocks (the second of which119// may or may not be incomplete).120byte[] tmp = new byte[blockSize];121// now encrypt the next-to-last block122for (int i = 0; i < blockSize; i++) {123tmp[i] = (byte) (plain[plainOffset+i] ^ r[i]);124}125byte[] tmp2 = new byte[blockSize];126embeddedCipher.encryptBlock(tmp, 0, tmp2, 0);127System.arraycopy(tmp2, 0, cipher,128cipherOffset+blockSize, nLeft);129// encrypt the last block130for (int i=0; i<nLeft; i++) {131tmp2[i] = (byte)132(plain[plainOffset+blockSize+i] ^ tmp2[i]);133}134embeddedCipher.encryptBlock(tmp2, 0, cipher, cipherOffset);135}136}137return plainLen;138}139140/**141* Performs decryption operation.142*143* <p>The input cipher text <code>cipher</code>, starting at144* <code>cipherOffset</code> and ending at145* <code>(cipherOffset + len - 1)</code>, is decrypted.146* The result is stored in <code>plain</code>, starting at147* <code>plainOffset</code>.148*149* <p>It is the application's responsibility to make sure that150* <code>cipherLen</code> is a multiple of the embedded cipher's block151* size, as any excess bytes are ignored.152*153* <p>It is also the application's responsibility to make sure that154* <code>init</code> has been called before this method is called.155* (This check is omitted here, to avoid double checking.)156*157* @param cipher the buffer with the input data to be decrypted158* @param cipherOffset the offset in <code>cipherOffset</code>159* @param cipherLen the length of the input data160* @param plain the buffer for the result161* @param plainOffset the offset in <code>plain</code>162* @return the number of bytes placed into <code>plain</code>163*/164int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,165byte[] plain, int plainOffset)166throws IllegalBlockSizeException {167if (cipherLen < blockSize) {168throw new IllegalBlockSizeException("input is too short!");169} else if (cipherLen == blockSize) {170decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);171} else {172// number of bytes in the last block173int nLeft = cipherLen % blockSize;174if (nLeft == 0) {175// swap the last two blocks before decryption176int lastBlkIndex = cipherOffset + cipherLen - blockSize;177int nextToLastBlkIndex =178cipherOffset + cipherLen - 2*blockSize;179byte[] tmp = new byte[2*blockSize];180System.arraycopy(cipher, lastBlkIndex, tmp, 0, blockSize);181System.arraycopy(cipher, nextToLastBlkIndex,182tmp, blockSize, blockSize);183int cipherLen2 = cipherLen-2*blockSize;184decrypt(cipher, cipherOffset, cipherLen2, plain, plainOffset);185decrypt(tmp, 0, 2*blockSize, plain, plainOffset+cipherLen2);186} else {187int newCipherLen = cipherLen-(blockSize+nLeft);188if (newCipherLen > 0) {189decrypt(cipher, cipherOffset, newCipherLen, plain,190plainOffset);191cipherOffset += newCipherLen;192plainOffset += newCipherLen;193}194// Do final CTS step for last two blocks (the second of which195// may or may not be incomplete).196197// now decrypt the next-to-last block198byte[] tmp = new byte[blockSize];199embeddedCipher.decryptBlock(cipher, cipherOffset, tmp, 0);200for (int i = 0; i < nLeft; i++) {201plain[plainOffset+blockSize+i] =202(byte) (cipher[cipherOffset+blockSize+i] ^ tmp[i]);203}204205// decrypt the last block206System.arraycopy(cipher, cipherOffset+blockSize, tmp, 0,207nLeft);208embeddedCipher.decryptBlock(tmp, 0, plain, plainOffset);209//System.arraycopy(r, 0, tmp, 0, r.length);210for (int i=0; i<blockSize; i++) {211plain[plainOffset+i] = (byte)212(plain[plainOffset+i]^r[i]);213}214}215}216return cipherLen;217}218}219220221