1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package javax.crypto; 19 20 import java.nio.ByteBuffer; 21 import java.security.AlgorithmParameters; 22 import java.security.InvalidAlgorithmParameterException; 23 import java.security.InvalidKeyException; 24 import java.security.Key; 25 import java.security.NoSuchAlgorithmException; 26 import java.security.SecureRandom; 27 import java.security.spec.AlgorithmParameterSpec; 28 29 /** 30 * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for 31 * cryptographic ciphers. 32 * <p> 33 * Implementers of cryptographic ciphers must implement all the abstract methods 34 * for every cipher they implement. {@code CipherSpi} instances are created 35 * along with ciphers when the {@link Cipher#getInstance} method is called. A 36 * {@code Cipher} is referenced by a <i>transformation</i>, which is a string 37 * that describes the operation (or set of operations), always consisting of the 38 * cipher's name and optionally followed by a mode and a padding, in the form: 39 * <ul> 40 * <li>"algorithm"</li>or 41 * <li>"algorithm/mode/padding"</li> 42 * </ul> 43 * The following behavior should be implemented for obtaining {@code Cipher} 44 * instances. 45 * <p> 46 * When one of the {@link Cipher#getInstance} factory methods is called with a 47 * <i>transformation</i> that is only an <i>algorithm</i>, check if the provider 48 * defines a {@code CipherSpi} for "algorithm", if so: return it, otherwise 49 * throw a {@link NoSuchAlgorithmException}. 50 * <p> 51 * The following rules apply when a <i>transformation</i> is of the form 52 * "algorithm/mode/padding": 53 * <ul> 54 * 1. The Provider has a {@code CipherSpi} subclass registered for 55 * "algorithm/mode/padding": return it, otherwise go to step 2. 56 * </ul> 57 * <ul> 58 * 2. The Provider has a {@code CipherSpi} subclass registered for 59 * "algorithm/mode": instantiate it, call 60 * {@link CipherSpi#engineSetPadding(String) engineSetPadding(String)} for the 61 * padding name and return it, otherwise go to step 3. 62 * </ul> 63 * <ul> 64 * 3. The Provider has a {@code CipherSpi} subclass registered for 65 * "algorithm//padding": instantiate it, call 66 * {@link CipherSpi#engineSetMode(String) engineSetMode(String)} for the mode 67 * name and return it, otherwise go to step 4. 68 * </ul> 69 * <ul> 70 * 4. The Provider has a {@code CipherSpi} subclass registered for "algorithm": 71 * instantiate it, call {@link CipherSpi#engineSetMode(String) 72 * engineSetMode(String)} for the mode name , call 73 * {@link CipherSpi#engineSetPadding(String) engineSetPadding(String)} for the 74 * padding name and return it, otherwise throw a 75 * {@link NoSuchAlgorithmException}. 76 * </ul> 77 * 78 * @see Cipher 79 */ 80 public abstract class CipherSpi { 81 82 /** 83 * Creates a new {@code CipherSpi} instance. 84 */ 85 public CipherSpi() { 86 } 87 88 /** 89 * Sets the mode for this cipher. 90 * 91 * @param mode 92 * the name of the cipher mode. 93 * @throws NoSuchAlgorithmException 94 * if the specified cipher mode is not supported by this 95 * provider. 96 */ 97 protected abstract void engineSetMode(String mode) 98 throws NoSuchAlgorithmException; 99 100 /** 101 * Sets the padding method for this cipher. 102 * 103 * @param padding 104 * the name of the padding method. 105 * @throws NoSuchPaddingException 106 * if the specified padding method is not supported by this 107 * cipher. 108 */ 109 protected abstract void engineSetPadding(String padding) 110 throws NoSuchPaddingException; 111 112 /** 113 * Returns the block size of this cipher (in bytes) 114 * 115 * @return the block size of this cipher, or zero if this cipher is not a 116 * block cipher. 117 */ 118 protected abstract int engineGetBlockSize(); 119 120 /** 121 * Returns the size for a buffer (in bytes), that the next call to {@code 122 * update} of {@code doFinal} would return, taking into account any buffered 123 * data from previous {@code update} calls and padding. 124 * <p> 125 * The actual output length of the next call to {@code update} or {@code 126 * doFinal} may be smaller than the length returned by this method. 127 * 128 * @param inputLen 129 * the length of the input (in bytes). 130 * @return the size for a buffer (in bytes). 131 */ 132 protected abstract int engineGetOutputSize(int inputLen); 133 134 /** 135 * Returns the Initialization Vector (IV) that was used to initialize this 136 * cipher or {@code null} if none was used. 137 * 138 * @return the Initialization Vector (IV), or {@code null} if none was used. 139 */ 140 protected abstract byte[] engineGetIV(); 141 142 /** 143 * Returns the parameters that where used to create this cipher instance. 144 * <p> 145 * These may be a the same parameters that were used to create this cipher 146 * instance, or may be a combination of default and random parameters, 147 * depending on the underlying cipher implementation. 148 * 149 * @return the parameters that where used to create this cipher instance, or 150 * {@code null} if this cipher instance does not have any parameters 151 * at all. 152 */ 153 protected abstract AlgorithmParameters engineGetParameters(); 154 155 /** 156 * Initializes this cipher instance with the specified key and a source of 157 * randomness. 158 * <p> 159 * The cipher will be initialized for the specified operation (one of: 160 * encryption, decryption, key wrapping or key unwrapping) depending on 161 * {@code opmode}. 162 * <p> 163 * If this cipher instance needs any algorithm parameters or random values 164 * that the specified key cannot provide, the underlying implementation of 165 * this cipher is supposed to generate the required parameters (using its 166 * provider or random values). Random values will be generated using {@code 167 * random}; 168 * <p> 169 * When a cipher instance is initialized by a call to any of the {@code 170 * init} methods, the state of the instance is overridden, means it is 171 * equivalent to creating a new instance and calling it {@code init} method. 172 * 173 * @param opmode 174 * the operation this cipher instance should be initialized for 175 * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 176 * WRAP_MODE} or {@code UNWRAP_MODE}). 177 * @param key 178 * the input key for the operation. 179 * @param random 180 * the source of randomness to use. 181 * @throws InvalidKeyException 182 * if the specified key cannot be used to initialize this cipher 183 * instance. 184 */ 185 protected abstract void engineInit(int opmode, Key key, SecureRandom random) 186 throws InvalidKeyException; 187 188 /** 189 * Initializes this cipher instance with the specified key, algorithm 190 * parameters and a source of randomness. 191 * <p> 192 * The cipher will be initialized for the specified operation (one of: 193 * encryption, decryption, key wrapping or key unwrapping) depending on 194 * {@code opmode}. 195 * <p> 196 * If this cipher instance needs any algorithm parameters and {@code params} 197 * is {@code null}, the underlying implementation of this cipher is supposed 198 * to generate the required parameters (using its provider or random 199 * values). Random values are generated using {@code random}. 200 * <p> 201 * When a cipher instance is initialized by a call to any of the {@code 202 * init} methods, the state of the instance is overridden, means it is 203 * equivalent to creating a new instance and calling it {@code init} method. 204 * 205 * @param opmode 206 * the operation this cipher instance should be initialized for 207 * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 208 * WRAP_MODE} or {@code UNWRAP_MODE}). 209 * @param key 210 * the input key for the operation. 211 * @param params 212 * the algorithm parameters. 213 * @param random 214 * the source of randomness to use. 215 * @throws InvalidKeyException 216 * if the specified key cannot be used to initialize this cipher 217 * instance. 218 * @throws InvalidAlgorithmParameterException 219 * it the specified parameters are inappropriate for this 220 * cipher. 221 */ 222 protected abstract void engineInit(int opmode, Key key, 223 AlgorithmParameterSpec params, SecureRandom random) 224 throws InvalidKeyException, InvalidAlgorithmParameterException; 225 226 /** 227 * Initializes this cipher instance with the specified key, algorithm 228 * parameters and a source of randomness. 229 * <p> 230 * The cipher will be initialized for the specified operation (one of: 231 * encryption, decryption, key wrapping or key unwrapping) depending on 232 * {@code opmode}. 233 * <p> 234 * If this cipher instance needs any algorithm parameters and {@code params} 235 * is {@code null}, the underlying implementation of this cipher is supposed 236 * to generate the required parameters (using its provider or random 237 * values). Random values are generated using {@code random}. 238 * <p> 239 * When a cipher instance is initialized by a call to any of the {@code 240 * init} methods, the state of the instance is overridden, means it is 241 * equivalent to creating a new instance and calling it {@code init} method. 242 * 243 * @param opmode 244 * the operation this cipher instance should be initialized for 245 * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 246 * WRAP_MODE} or {@code UNWRAP_MODE}). 247 * @param key 248 * the input key for the operation. 249 * @param params 250 * the algorithm parameters. 251 * @param random 252 * the source of randomness to use. 253 * @throws InvalidKeyException 254 * if the specified key cannot be used to initialize this cipher 255 * instance. 256 * @throws InvalidAlgorithmParameterException 257 * if the specified parameters are inappropriate for this 258 * cipher. 259 */ 260 protected abstract void engineInit(int opmode, Key key, 261 AlgorithmParameters params, SecureRandom random) 262 throws InvalidKeyException, InvalidAlgorithmParameterException; 263 264 /** 265 * Continues a multi-part transformation (encryption or decryption). The 266 * transformed bytes are returned. 267 * 268 * @param input 269 * the input bytes to transform. 270 * @param inputOffset 271 * the offset in the input to start. 272 * @param inputLen 273 * the length of the input to transform. 274 * @return the transformed bytes in a new buffer, or {@code null} if the 275 * input has zero length. 276 * @throws IllegalStateException 277 * if this cipher instance is not initialized for encryption or 278 * decryption. 279 * @throws IllegalArgumentException 280 * if the input is null, or if {@code inputOffset} and {@code 281 * inputLen} do not specify a valid chunk in the input buffer. 282 */ 283 protected abstract byte[] engineUpdate(byte[] input, int inputOffset, 284 int inputLen); 285 286 /** 287 * Continues a multi-part transformation (encryption or decryption). The 288 * transformed bytes are stored in the {@code output} buffer. 289 * <p> 290 * If the size of the {@code output} buffer is too small to hold the result, 291 * a {@code ShortBufferException} is thrown. Use 292 * {@link Cipher#getOutputSize getOutputSize} to check for the size of the 293 * output buffer. 294 * 295 * @param input 296 * the input bytes to transform. 297 * @param inputOffset 298 * the offset in the input to start. 299 * @param inputLen 300 * the length of the input to transform. 301 * @param output 302 * the output buffer. 303 * @param outputOffset 304 * the offset in the output buffer. 305 * @return the number of bytes placed in output. 306 * @throws ShortBufferException 307 * if the size of the {@code output} buffer is too small. 308 */ 309 protected abstract int engineUpdate(byte[] input, int inputOffset, 310 int inputLen, byte[] output, int outputOffset) 311 throws ShortBufferException; 312 313 /** 314 * Continues a multi-part transformation (encryption or decryption). The 315 * {@code input.remaining()} bytes starting at {@code input.position()} are 316 * transformed and stored in the {@code output} buffer. 317 * <p> 318 * If the {@code output.remaining()} is too small to hold the transformed 319 * bytes a {@code ShortBufferException} is thrown. Use 320 * {@link Cipher#getOutputSize getOutputSize} to check for the size of the 321 * output buffer. 322 * 323 * @param input 324 * the input buffer to transform. 325 * @param output 326 * the output buffer to store the result within. 327 * @return the number of bytes stored in the output buffer. 328 * @throws ShortBufferException 329 * if the size of the {@code output} buffer is too small. 330 */ 331 protected int engineUpdate(ByteBuffer input, ByteBuffer output) 332 throws ShortBufferException { 333 if (input == null) { 334 throw new NullPointerException("input == null"); 335 } 336 if (output == null) { 337 throw new NullPointerException("output == null"); 338 } 339 int position = input.position(); 340 int limit = input.limit(); 341 if ((limit - position) <= 0) { 342 return 0; 343 } 344 byte[] bInput; 345 byte[] bOutput; 346 if (input.hasArray()) { 347 bInput = input.array(); 348 int offset = input.arrayOffset(); 349 bOutput = engineUpdate(bInput, offset + position, limit - position); 350 input.position(limit); 351 } else { 352 bInput = new byte[limit - position]; 353 input.get(bInput); 354 bOutput = engineUpdate(bInput, 0, limit - position); 355 } 356 if (bOutput == null) { 357 return 0; 358 } 359 if (output.remaining() < bOutput.length) { 360 throw new ShortBufferException("output buffer too small"); 361 } 362 try { 363 output.put(bOutput); 364 } catch (java.nio.BufferOverflowException e) { 365 throw new ShortBufferException("output buffer too small"); 366 } 367 return bOutput.length; 368 } 369 370 /** 371 * Finishes a multi-part transformation (encryption or decryption). 372 * <p> 373 * Processes the {@code inputLen} bytes in {@code input} buffer at {@code 374 * inputOffset}, and any bytes that have been buffered in previous {@code 375 * update} calls. 376 * 377 * @param input 378 * the input buffer. 379 * @param inputOffset 380 * the offset in the input buffer. 381 * @param inputLen 382 * the length of the input. 383 * @return the final bytes from the transformation. 384 * @throws IllegalBlockSizeException 385 * if the size of the resulting bytes is not a multiple of the 386 * cipher block size. 387 * @throws BadPaddingException 388 * if the padding of the data does not match the padding scheme. 389 */ 390 protected abstract byte[] engineDoFinal(byte[] input, int inputOffset, 391 int inputLen) throws IllegalBlockSizeException, BadPaddingException; 392 393 /** 394 * Finishes a multi-part transformation (encryption or decryption). 395 * <p> 396 * Processes the {@code inputLen} bytes in {@code input} buffer at 397 * {@code inputOffset}, and any bytes that have been buffered in previous 398 * {@code update} calls. 399 * 400 * @param input 401 * the input buffer. 402 * @param inputOffset 403 * the offset in the input buffer. 404 * @param inputLen 405 * the length of the input. 406 * @param output 407 * the output buffer for the transformed bytes. 408 * @param outputOffset 409 * the offset in the output buffer. 410 * @return the number of bytes placed in the output buffer. 411 * @throws ShortBufferException 412 * if the size of the {@code output} buffer is too small. 413 * @throws IllegalBlockSizeException 414 * if the size of the resulting bytes is not a multiple of the 415 * cipher block size. 416 * @throws BadPaddingException 417 * if the padding of the data does not match the padding scheme. 418 */ 419 protected abstract int engineDoFinal(byte[] input, int inputOffset, 420 int inputLen, byte[] output, int outputOffset) 421 throws ShortBufferException, IllegalBlockSizeException, 422 BadPaddingException; 423 424 /** 425 * Finishes a multi-part transformation (encryption or decryption). 426 * <p> 427 * Processes the {@code input.remaining()} bytes in {@code input} buffer at 428 * {@code input.position()}, and any bytes that have been buffered in 429 * previous {@code update} calls. The transformed bytes are placed into 430 * {@code output} buffer. 431 * 432 * @param input 433 * the input buffer. 434 * @param output 435 * the output buffer. 436 * @return the number of bytes placed into the output buffer. 437 * @throws ShortBufferException 438 * if the size of the {@code output} buffer is too small. 439 * @throws IllegalBlockSizeException 440 * if the size of the resulting bytes is not a multiple of the 441 * cipher block size. 442 * @throws BadPaddingException 443 * if the padding of the data does not match the padding scheme. 444 * @throws IllegalArgumentException 445 * if the input buffer and the output buffer are the same 446 * object. 447 * @throws IllegalStateException 448 * if this cipher instance is not initialized for encryption or 449 * decryption. 450 */ 451 protected int engineDoFinal(ByteBuffer input, ByteBuffer output) 452 throws ShortBufferException, IllegalBlockSizeException, 453 BadPaddingException { 454 if (input == null) { 455 throw new NullPointerException("input == null"); 456 } 457 if (output == null) { 458 throw new NullPointerException("output == null"); 459 } 460 int position = input.position(); 461 int limit = input.limit(); 462 463 if ((limit - position) <= 0) { 464 return 0; 465 } 466 byte[] bInput; 467 byte[] bOutput; 468 469 if (input.hasArray()) { 470 bInput = input.array(); 471 int offset = input.arrayOffset(); 472 bOutput = engineDoFinal(bInput, offset + position, limit - position); 473 input.position(limit); 474 } else { 475 bInput = new byte[limit - position]; 476 input.get(bInput); 477 bOutput = engineDoFinal(bInput, 0, limit - position); 478 } 479 if (output.remaining() < bOutput.length) { 480 throw new ShortBufferException("output buffer too small"); 481 } 482 try { 483 output.put(bOutput); 484 } catch (java.nio.BufferOverflowException e) { 485 throw new ShortBufferException("output buffer too small"); 486 } 487 return bOutput.length; 488 } 489 490 /** 491 * Wraps a key using this cipher instance. This method has been added to 492 * this class (for backwards compatibility, it cannot be abstract). If this 493 * method is not overridden, it throws an {@code 494 * UnsupportedOperationException}. 495 * 496 * @param key 497 * the key to wrap. 498 * @return the wrapped key 499 * @throws IllegalBlockSizeException 500 * if the size of the resulting bytes is not a multiple of the 501 * cipher block size. 502 * @throws InvalidKeyException 503 * if this cipher instance cannot wrap this key. 504 */ 505 protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { 506 throw new UnsupportedOperationException(); 507 } 508 509 /** 510 * Unwraps a key using this cipher instance. 511 * <p> 512 * This method has been added to this class (for backwards compatibility, it 513 * cannot be abstract). If this method is not overridden, it throws an 514 * {@code UnsupportedOperationException}. 515 * 516 * @param wrappedKey 517 * the wrapped key to unwrap. 518 * @param wrappedKeyAlgorithm 519 * the algorithm for the wrapped key. 520 * @param wrappedKeyType 521 * the type of the wrapped key (one of: {@code SECRET_KEY}, 522 * {@code PRIVATE_KEY} or {@code PUBLIC_KEY}) 523 * @return the unwrapped key. 524 * @throws InvalidKeyException 525 * if the {@code wrappedKey} cannot be unwrapped to a key of 526 * type {@code wrappedKeyType} for the {@code 527 * wrappedKeyAlgorithm}. 528 * @throws NoSuchAlgorithmException 529 * if no provider can be found that can create a key of type 530 * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. 531 */ 532 protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 533 int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { 534 throw new UnsupportedOperationException(); 535 } 536 537 /** 538 * Returns the size of a specified key object in bits. This method has been 539 * added to this class (for backwards compatibility, it cannot be abstract). 540 * If this method is not overridden, it throws an {@code 541 * UnsupportedOperationException}. 542 * 543 * @param key 544 * the key to get the size for. 545 * @return the size of a specified key object in bits. 546 * @throws InvalidKeyException 547 * if the size of the key cannot be determined by this 548 * implementation. 549 */ 550 protected int engineGetKeySize(Key key) throws InvalidKeyException { 551 throw new UnsupportedOperationException(); 552 } 553 } 554