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 * Continues a multi-part transformation (encryption or decryption) with 372 * Authenticated Additional Data (AAD). AAD may only be added after the 373 * {@code Cipher} is initialized and before any data is passed to the 374 * instance. 375 * <p> 376 * This is only usable with cipher modes that support Authenticated 377 * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). 378 * 379 * @param input bytes of AAD to use with the cipher 380 * @param inputOffset offset within bytes of additional data to add to cipher 381 * @param inputLen length of bytes of additional data to add to cipher 382 * @throws IllegalStateException 383 * if this cipher instance is not initialized for encryption or 384 * decryption. 385 * @throws IllegalArgumentException 386 * if {@code input} is {@code null}, or if {@code inputOffset} and 387 * {@code inputLen} do not specify a valid chunk in the input 388 * buffer. 389 * @throws UnsupportedOperationException if the cipher does not support AEAD 390 * @since 1.7 391 */ 392 protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { 393 throw new UnsupportedOperationException( 394 "This cipher does not support Authenticated Encryption with Additional Data"); 395 } 396 397 /** 398 * Continues a multi-part transformation (encryption or decryption). The 399 * {@code input.remaining()} bytes starting at {@code input.position()} are 400 * used for the Additional Authenticated Data (AAD). AAD may only be added 401 * after the {@code Cipher} is initialized and before any data is passed to 402 * the instance. 403 * <p> 404 * This is only usable with cipher modes that support Authenticated 405 * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). 406 * 407 * @param input the input buffer to transform. 408 * @since 1.7 409 */ 410 protected void engineUpdateAAD(ByteBuffer input) { 411 if (input == null) { 412 throw new NullPointerException("input == null"); 413 } 414 int position = input.position(); 415 int limit = input.limit(); 416 if ((limit - position) <= 0) { 417 return; 418 } 419 byte[] bInput; 420 if (input.hasArray()) { 421 bInput = input.array(); 422 int offset = input.arrayOffset(); 423 engineUpdateAAD(bInput, offset + position, limit - position); 424 input.position(limit); 425 } else { 426 int len = limit - position; 427 bInput = new byte[len]; 428 input.get(bInput); 429 engineUpdateAAD(bInput, 0, len); 430 } 431 } 432 433 /** 434 * Finishes a multi-part transformation (encryption or decryption). 435 * <p> 436 * Processes the {@code inputLen} bytes in {@code input} buffer at {@code 437 * inputOffset}, and any bytes that have been buffered in previous {@code 438 * update} calls. 439 * 440 * @param input 441 * the input buffer. 442 * @param inputOffset 443 * the offset in the input buffer. 444 * @param inputLen 445 * the length of the input. 446 * @return the final bytes from the transformation. 447 * @throws IllegalBlockSizeException 448 * if the size of the resulting bytes is not a multiple of the 449 * cipher block size. 450 * @throws BadPaddingException 451 * if the padding of the data does not match the padding scheme. 452 */ 453 protected abstract byte[] engineDoFinal(byte[] input, int inputOffset, 454 int inputLen) throws IllegalBlockSizeException, BadPaddingException; 455 456 /** 457 * Finishes a multi-part transformation (encryption or decryption). 458 * <p> 459 * Processes the {@code inputLen} bytes in {@code input} buffer at 460 * {@code inputOffset}, and any bytes that have been buffered in previous 461 * {@code update} calls. 462 * 463 * @param input 464 * the input buffer. 465 * @param inputOffset 466 * the offset in the input buffer. 467 * @param inputLen 468 * the length of the input. 469 * @param output 470 * the output buffer for the transformed bytes. 471 * @param outputOffset 472 * the offset in the output buffer. 473 * @return the number of bytes placed in the output buffer. 474 * @throws ShortBufferException 475 * if the size of the {@code output} buffer is too small. 476 * @throws IllegalBlockSizeException 477 * if the size of the resulting bytes is not a multiple of the 478 * cipher block size. 479 * @throws BadPaddingException 480 * if the padding of the data does not match the padding scheme. 481 */ 482 protected abstract int engineDoFinal(byte[] input, int inputOffset, 483 int inputLen, byte[] output, int outputOffset) 484 throws ShortBufferException, IllegalBlockSizeException, 485 BadPaddingException; 486 487 /** 488 * Finishes a multi-part transformation (encryption or decryption). 489 * <p> 490 * Processes the {@code input.remaining()} bytes in {@code input} buffer at 491 * {@code input.position()}, and any bytes that have been buffered in 492 * previous {@code update} calls. The transformed bytes are placed into 493 * {@code output} buffer. 494 * 495 * @param input 496 * the input buffer. 497 * @param output 498 * the output buffer. 499 * @return the number of bytes placed into the output buffer. 500 * @throws ShortBufferException 501 * if the size of the {@code output} buffer is too small. 502 * @throws IllegalBlockSizeException 503 * if the size of the resulting bytes is not a multiple of the 504 * cipher block size. 505 * @throws BadPaddingException 506 * if the padding of the data does not match the padding scheme. 507 * @throws IllegalArgumentException 508 * if the input buffer and the output buffer are the same 509 * object. 510 * @throws IllegalStateException 511 * if this cipher instance is not initialized for encryption or 512 * decryption. 513 */ 514 protected int engineDoFinal(ByteBuffer input, ByteBuffer output) 515 throws ShortBufferException, IllegalBlockSizeException, 516 BadPaddingException { 517 if (input == null) { 518 throw new NullPointerException("input == null"); 519 } 520 if (output == null) { 521 throw new NullPointerException("output == null"); 522 } 523 int position = input.position(); 524 int limit = input.limit(); 525 526 if ((limit - position) <= 0) { 527 return 0; 528 } 529 byte[] bInput; 530 byte[] bOutput; 531 532 if (input.hasArray()) { 533 bInput = input.array(); 534 int offset = input.arrayOffset(); 535 bOutput = engineDoFinal(bInput, offset + position, limit - position); 536 input.position(limit); 537 } else { 538 bInput = new byte[limit - position]; 539 input.get(bInput); 540 bOutput = engineDoFinal(bInput, 0, limit - position); 541 } 542 if (output.remaining() < bOutput.length) { 543 throw new ShortBufferException("output buffer too small"); 544 } 545 try { 546 output.put(bOutput); 547 } catch (java.nio.BufferOverflowException e) { 548 throw new ShortBufferException("output buffer too small"); 549 } 550 return bOutput.length; 551 } 552 553 /** 554 * Wraps a key using this cipher instance. This method has been added to 555 * this class (for backwards compatibility, it cannot be abstract). If this 556 * method is not overridden, it throws an {@code 557 * UnsupportedOperationException}. 558 * 559 * @param key 560 * the key to wrap. 561 * @return the wrapped key 562 * @throws IllegalBlockSizeException 563 * if the size of the resulting bytes is not a multiple of the 564 * cipher block size. 565 * @throws InvalidKeyException 566 * if this cipher instance cannot wrap this key. 567 */ 568 protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { 569 throw new UnsupportedOperationException(); 570 } 571 572 /** 573 * Unwraps a key using this cipher instance. 574 * <p> 575 * This method has been added to this class (for backwards compatibility, it 576 * cannot be abstract). If this method is not overridden, it throws an 577 * {@code UnsupportedOperationException}. 578 * 579 * @param wrappedKey 580 * the wrapped key to unwrap. 581 * @param wrappedKeyAlgorithm 582 * the algorithm for the wrapped key. 583 * @param wrappedKeyType 584 * the type of the wrapped key (one of: {@code SECRET_KEY}, 585 * {@code PRIVATE_KEY} or {@code PUBLIC_KEY}) 586 * @return the unwrapped key. 587 * @throws InvalidKeyException 588 * if the {@code wrappedKey} cannot be unwrapped to a key of 589 * type {@code wrappedKeyType} for the {@code 590 * wrappedKeyAlgorithm}. 591 * @throws NoSuchAlgorithmException 592 * if no provider can be found that can create a key of type 593 * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. 594 */ 595 protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 596 int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { 597 throw new UnsupportedOperationException(); 598 } 599 600 /** 601 * Returns the size of a specified key object in bits. This method has been 602 * added to this class (for backwards compatibility, it cannot be abstract). 603 * If this method is not overridden, it throws an {@code 604 * UnsupportedOperationException}. 605 * 606 * @param key 607 * the key to get the size for. 608 * @return the size of a specified key object in bits. 609 * @throws InvalidKeyException 610 * if the size of the key cannot be determined by this 611 * implementation. 612 */ 613 protected int engineGetKeySize(Key key) throws InvalidKeyException { 614 throw new UnsupportedOperationException(); 615 } 616 } 617