1 /* 2 * Copyright (c) 1997, 2018, 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 26 package com.sun.crypto.provider; 27 28 import java.security.InvalidKeyException; 29 import java.security.ProviderException; 30 import sun.security.util.ArrayUtil; 31 32 /** 33 * This class represents ciphers in cipher-feedback (CFB) mode. 34 * 35 * <p>This mode is implemented independently of a particular cipher. 36 * Ciphers to which this mode should apply (e.g., DES) must be 37 * <i>plugged-in</i> using the constructor. 38 * 39 * <p>NOTE: This class does not deal with buffering or padding. 40 * 41 * @author Gigi Ankeny 42 */ 43 44 final class CipherFeedback extends FeedbackCipher { 45 46 /* 47 * encrypt/decrypt output buffer 48 */ 49 private final byte[] k; 50 51 /* 52 * register value, initialized with iv 53 */ 54 private final byte[] register; 55 56 /* 57 * number of bytes for each stream unit, defaults to the blocksize 58 * of the embedded cipher 59 */ 60 private int numBytes; 61 62 // variables for save/restore calls 63 private byte[] registerSave = null; 64 CipherFeedback(SymmetricCipher embeddedCipher, int numBytes)65 CipherFeedback(SymmetricCipher embeddedCipher, int numBytes) { 66 super(embeddedCipher); 67 if (numBytes > blockSize) { 68 numBytes = blockSize; 69 } 70 this.numBytes = numBytes; 71 k = new byte[blockSize]; 72 register = new byte[blockSize]; 73 } 74 75 /** 76 * Gets the name of this feedback mode. 77 * 78 * @return the string <code>CFB</code> 79 */ getFeedback()80 String getFeedback() { 81 return "CFB"; 82 } 83 84 /** 85 * Initializes the cipher in the specified mode with the given key 86 * and iv. 87 * 88 * @param decrypting flag indicating encryption or decryption 89 * @param algorithm the algorithm name 90 * @param key the key 91 * @param iv the iv 92 * 93 * @exception InvalidKeyException if the given key is inappropriate for 94 * initializing this cipher 95 */ init(boolean decrypting, String algorithm, byte[] key, byte[] iv)96 void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) 97 throws InvalidKeyException { 98 if ((key == null) || (iv == null) || (iv.length != blockSize)) { 99 throw new InvalidKeyException("Internal error"); 100 } 101 this.iv = iv; 102 reset(); 103 // always encrypt mode for embedded cipher 104 embeddedCipher.init(false, algorithm, key); 105 } 106 107 /** 108 * Resets the iv to its original value. 109 * This is used when doFinal is called in the Cipher class, so that the 110 * cipher can be reused (with its original iv). 111 */ reset()112 void reset() { 113 System.arraycopy(iv, 0, register, 0, blockSize); 114 } 115 116 /** 117 * Save the current content of this cipher. 118 */ save()119 void save() { 120 if (registerSave == null) { 121 registerSave = new byte[blockSize]; 122 } 123 System.arraycopy(register, 0, registerSave, 0, blockSize); 124 } 125 126 /** 127 * Restores the content of this cipher to the previous saved one. 128 */ restore()129 void restore() { 130 System.arraycopy(registerSave, 0, register, 0, blockSize); 131 } 132 133 /** 134 * Performs encryption operation. 135 * 136 * <p>The input plain text <code>plain</code>, starting at 137 * <code>plainOffset</code> and ending at 138 * <code>(plainOffset + plainLen - 1)</code>, is encrypted. 139 * The result is stored in <code>cipher</code>, starting at 140 * <code>cipherOffset</code>. 141 * 142 * @param plain the buffer with the input data to be encrypted 143 * @param plainOffset the offset in <code>plain</code> 144 * @param plainLen the length of the input data 145 * @param cipher the buffer for the result 146 * @param cipherOffset the offset in <code>cipher</code> 147 * @exception ProviderException if <code>plainLen</code> is not 148 * a multiple of the <code>numBytes</code> 149 * @return the length of the encrypted data 150 */ encrypt(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset)151 int encrypt(byte[] plain, int plainOffset, int plainLen, 152 byte[] cipher, int cipherOffset) { 153 ArrayUtil.blockSizeCheck(plainLen, numBytes); 154 ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen); 155 ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen); 156 157 int nShift = blockSize - numBytes; 158 int loopCount = plainLen / numBytes; 159 160 for (; loopCount > 0 ; 161 plainOffset += numBytes, cipherOffset += numBytes, 162 loopCount--) { 163 embeddedCipher.encryptBlock(register, 0, k, 0); 164 if (nShift != 0) { 165 System.arraycopy(register, numBytes, register, 0, nShift); 166 } 167 for (int i = 0; i < numBytes; i++) { 168 register[nShift + i] = cipher[i + cipherOffset] = 169 (byte)(k[i] ^ plain[i + plainOffset]); 170 } 171 } 172 return plainLen; 173 } 174 175 /** 176 * Performs the last encryption operation. 177 * 178 * <p>The input plain text <code>plain</code>, starting at 179 * <code>plainOffset</code> and ending at 180 * <code>(plainOffset + plainLen - 1)</code>, is encrypted. 181 * The result is stored in <code>cipher</code>, starting at 182 * <code>cipherOffset</code>. 183 * 184 * @param plain the buffer with the input data to be encrypted 185 * @param plainOffset the offset in <code>plain</code> 186 * @param plainLen the length of the input data 187 * @param cipher the buffer for the result 188 * @param cipherOffset the offset in <code>cipher</code> 189 * @return the number of bytes placed into <code>cipher</code> 190 */ encryptFinal(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset)191 int encryptFinal(byte[] plain, int plainOffset, int plainLen, 192 byte[] cipher, int cipherOffset) { 193 194 int oddBytes = plainLen % numBytes; 195 int len = encrypt(plain, plainOffset, (plainLen - oddBytes), 196 cipher, cipherOffset); 197 plainOffset += len; 198 cipherOffset += len; 199 if (oddBytes != 0) { 200 embeddedCipher.encryptBlock(register, 0, k, 0); 201 for (int i = 0; i < oddBytes; i++) { 202 cipher[i + cipherOffset] = 203 (byte)(k[i] ^ plain[i + plainOffset]); 204 } 205 } 206 return plainLen; 207 } 208 209 /** 210 * Performs decryption operation. 211 * 212 * <p>The input cipher text <code>cipher</code>, starting at 213 * <code>cipherOffset</code> and ending at 214 * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted. 215 * The result is stored in <code>plain</code>, starting at 216 * <code>plainOffset</code>. 217 * 218 * @param cipher the buffer with the input data to be decrypted 219 * @param cipherOffset the offset in <code>cipherOffset</code> 220 * @param cipherLen the length of the input data 221 * @param plain the buffer for the result 222 * @param plainOffset the offset in <code>plain</code> 223 * @exception ProviderException if <code>cipherLen</code> is not 224 * a multiple of the <code>numBytes</code> 225 * @return the length of the decrypted data 226 */ decrypt(byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset)227 int decrypt(byte[] cipher, int cipherOffset, int cipherLen, 228 byte[] plain, int plainOffset) { 229 230 ArrayUtil.blockSizeCheck(cipherLen, numBytes); 231 ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen); 232 ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen); 233 234 int nShift = blockSize - numBytes; 235 int loopCount = cipherLen / numBytes; 236 237 for (; loopCount > 0; 238 plainOffset += numBytes, cipherOffset += numBytes, 239 loopCount--) { 240 embeddedCipher.encryptBlock(register, 0, k, 0); 241 if (nShift != 0) { 242 System.arraycopy(register, numBytes, register, 0, nShift); 243 } 244 for (int i = 0; i < numBytes; i++) { 245 register[i + nShift] = cipher[i + cipherOffset]; 246 plain[i + plainOffset] 247 = (byte)(cipher[i + cipherOffset] ^ k[i]); 248 } 249 } 250 return cipherLen; 251 } 252 253 /** 254 * Performs the last decryption operation. 255 * 256 * <p>The input cipher text <code>cipher</code>, starting at 257 * <code>cipherOffset</code> and ending at 258 * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted. 259 * The result is stored in <code>plain</code>, starting at 260 * <code>plainOffset</code>. 261 * 262 * @param cipher the buffer with the input data to be decrypted 263 * @param cipherOffset the offset in <code>cipherOffset</code> 264 * @param cipherLen the length of the input data 265 * @param plain the buffer for the result 266 * @param plainOffset the offset in <code>plain</code> 267 * @return the length of the decrypted data 268 */ decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset)269 int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, 270 byte[] plain, int plainOffset) { 271 272 int oddBytes = cipherLen % numBytes; 273 int len = decrypt(cipher, cipherOffset, (cipherLen - oddBytes), 274 plain, plainOffset); 275 cipherOffset += len; 276 plainOffset += len; 277 if (oddBytes != 0) { 278 embeddedCipher.encryptBlock(register, 0, k, 0); 279 for (int i = 0; i < oddBytes; i++) { 280 plain[i + plainOffset] 281 = (byte)(cipher[i + cipherOffset] ^ k[i]); 282 } 283 } 284 return cipherLen; 285 } 286 } 287