1/* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.crypto.provider; 27 28import java.security.InvalidKeyException; 29import java.security.ProviderException; 30 31 32/** 33 * This class represents ciphers in Plaintext Cipher Block Chaining (PCBC) 34 * mode. 35 * 36 * <p>This mode is implemented independently of a particular cipher. 37 * Ciphers to which this mode should apply (e.g., DES) must be 38 * <i>plugged-in</i> using the constructor. 39 * 40 * <p>NOTE: This class does not deal with buffering or padding. 41 * 42 * @author Gigi Ankeny 43 */ 44 45final class PCBC extends FeedbackCipher { 46 47 /* 48 * output buffer 49 */ 50 private final byte[] k; 51 52 // variables for save/restore calls 53 private byte[] kSave = null; 54 55 PCBC(SymmetricCipher embeddedCipher) { 56 super(embeddedCipher); 57 k = new byte[blockSize]; 58 } 59 60 /** 61 * Gets the name of this feedback mode. 62 * 63 * @return the string <code>PCBC</code> 64 */ 65 String getFeedback() { 66 return "PCBC"; 67 } 68 69 /** 70 * Initializes the cipher in the specified mode with the given key 71 * and iv. 72 * 73 * @param decrypting flag indicating encryption or decryption 74 * @param algorithm the algorithm name 75 * @param key the key 76 * @param iv the iv 77 * 78 * @exception InvalidKeyException if the given key is inappropriate for 79 * initializing this cipher 80 */ 81 void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) 82 throws InvalidKeyException { 83 if ((key == null) || (iv == null) || (iv.length != blockSize)) { 84 throw new InvalidKeyException("Internal error"); 85 } 86 this.iv = iv; 87 reset(); 88 embeddedCipher.init(decrypting, algorithm, key); 89 } 90 91 /** 92 * Resets the iv to its original value. 93 * This is used when doFinal is called in the Cipher class, so that the 94 * cipher can be reused (with its original iv). 95 */ 96 void reset() { 97 System.arraycopy(iv, 0, k, 0, blockSize); 98 } 99 100 /** 101 * Save the current content of this cipher. 102 */ 103 void save() { 104 if (kSave == null) { 105 kSave = new byte[blockSize]; 106 } 107 System.arraycopy(k, 0, kSave, 0, blockSize); 108 109 } 110 111 /** 112 * Restores the content of this cipher to the previous saved one. 113 */ 114 void restore() { 115 System.arraycopy(kSave, 0, k, 0, blockSize); 116 } 117 118 /** 119 * Performs encryption operation. 120 * 121 * <p>The input plain text <code>plain</code>, starting at 122 * <code>plainOffset</code> and ending at 123 * <code>(plainOffset + plainLen - 1)</code>, is encrypted. 124 * The result is stored in <code>cipher</code>, starting at 125 * <code>cipherOffset</code>. 126 * 127 * @param plain the buffer with the input data to be encrypted 128 * @param plainOffset the offset in <code>plain</code> 129 * @param plainLen the length of the input data 130 * @param cipher the buffer for the result 131 * @param cipherOffset the offset in <code>cipher</code> 132 * @exception ProviderException if <code>plainLen</code> is not 133 * a multiple of the block size 134 * @return the length of the encrypted data 135 */ 136 int encrypt(byte[] plain, int plainOffset, int plainLen, 137 byte[] cipher, int cipherOffset) 138 { 139 if ((plainLen % blockSize) != 0) { 140 throw new ProviderException("Internal error in input buffering"); 141 } 142 int i; 143 int endIndex = plainOffset + plainLen; 144 145 for (; plainOffset < endIndex; 146 plainOffset += blockSize, cipherOffset += blockSize) { 147 for (i = 0; i < blockSize; i++) { 148 k[i] ^= plain[i + plainOffset]; 149 } 150 embeddedCipher.encryptBlock(k, 0, cipher, cipherOffset); 151 for (i = 0; i < blockSize; i++) { 152 k[i] = (byte)(plain[i + plainOffset] ^ cipher[i + cipherOffset]); 153 } 154 } 155 return plainLen; 156 } 157 158 /** 159 * Performs decryption operation. 160 * 161 * <p>The input cipher text <code>cipher</code>, starting at 162 * <code>cipherOffset</code> and ending at 163 * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted. 164 * The result is stored in <code>plain</code>, starting at 165 * <code>plainOffset</code>. 166 * 167 * @param cipher the buffer with the input data to be decrypted 168 * @param cipherOffset the offset in <code>cipherOffset</code> 169 * @param cipherLen the length of the input data 170 * @param plain the buffer for the result 171 * @param plainOffset the offset in <code>plain</code> 172 * @exception ProviderException if <code>cipherLen</code> is not 173 * a multiple of the block size 174 * @return the length of the decrypted data 175 */ 176 int decrypt(byte[] cipher, int cipherOffset, int cipherLen, 177 byte[] plain, int plainOffset) 178 { 179 if ((cipherLen % blockSize) != 0) { 180 throw new ProviderException("Internal error in input buffering"); 181 } 182 int i; 183 int endIndex = cipherOffset + cipherLen; 184 185 for (; cipherOffset < endIndex; 186 plainOffset += blockSize, cipherOffset += blockSize) { 187 embeddedCipher.decryptBlock(cipher, cipherOffset, 188 plain, plainOffset); 189 for (i = 0; i < blockSize; i++) { 190 plain[i + plainOffset] ^= k[i]; 191 } 192 for (i = 0; i < blockSize; i++) { 193 k[i] = (byte)(plain[i + plainOffset] ^ cipher[i + cipherOffset]); 194 } 195 } 196 return cipherLen; 197 } 198} 199