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 */ CipherSpi()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 */ engineSetMode(String mode)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 */ engineSetPadding(String padding)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 */ engineGetBlockSize()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 */ engineGetOutputSize(int inputLen)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 */ engineGetIV()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 */ engineGetParameters()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 */ engineInit(int opmode, Key key, SecureRandom random)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 */ engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)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 */ engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)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 */ engineUpdate(byte[] input, int inputOffset, int inputLen)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 */ engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)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 */ engineUpdate(ByteBuffer input, ByteBuffer output)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 (output.remaining() < bOutput.length) { 357 throw new ShortBufferException("output buffer too small"); 358 } 359 try { 360 output.put(bOutput); 361 } catch (java.nio.BufferOverflowException e) { 362 throw new ShortBufferException("output buffer too small"); 363 } 364 return bOutput.length; 365 } 366 367 /** 368 * Finishes a multi-part transformation (encryption or decryption). 369 * <p> 370 * Processes the {@code inputLen} bytes in {@code input} buffer at {@code 371 * inputOffset}, and any bytes that have been buffered in previous {@code 372 * update} calls. 373 * 374 * @param input 375 * the input buffer. 376 * @param inputOffset 377 * the offset in the input buffer. 378 * @param inputLen 379 * the length of the input. 380 * @return the final bytes from the transformation. 381 * @throws IllegalBlockSizeException 382 * if the size of the resulting bytes is not a multiple of the 383 * cipher block size. 384 * @throws BadPaddingException 385 * if the padding of the data does not match the padding scheme. 386 */ engineDoFinal(byte[] input, int inputOffset, int inputLen)387 protected abstract byte[] engineDoFinal(byte[] input, int inputOffset, 388 int inputLen) throws IllegalBlockSizeException, BadPaddingException; 389 390 /** 391 * Finishes a multi-part transformation (encryption or decryption). 392 * <p> 393 * Processes the {@code inputLen} bytes in {@code input} buffer at 394 * {@code inputOffset}, and any bytes that have been buffered in previous 395 * {@code update} calls. 396 * 397 * @param input 398 * the input buffer. 399 * @param inputOffset 400 * the offset in the input buffer. 401 * @param inputLen 402 * the length of the input. 403 * @param output 404 * the output buffer for the transformed bytes. 405 * @param outputOffset 406 * the offset in the output buffer. 407 * @return the number of bytes placed in the output buffer. 408 * @throws ShortBufferException 409 * if the size of the {@code output} buffer is too small. 410 * @throws IllegalBlockSizeException 411 * if the size of the resulting bytes is not a multiple of the 412 * cipher block size. 413 * @throws BadPaddingException 414 * if the padding of the data does not match the padding scheme. 415 */ engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)416 protected abstract int engineDoFinal(byte[] input, int inputOffset, 417 int inputLen, byte[] output, int outputOffset) 418 throws ShortBufferException, IllegalBlockSizeException, 419 BadPaddingException; 420 421 /** 422 * Finishes a multi-part transformation (encryption or decryption). 423 * <p> 424 * Processes the {@code input.remaining()} bytes in {@code input} buffer at 425 * {@code input.position()}, and any bytes that have been buffered in 426 * previous {@code update} calls. The transformed bytes are placed into 427 * {@code output} buffer. 428 * 429 * @param input 430 * the input buffer. 431 * @param output 432 * the output buffer. 433 * @return the number of bytes placed into the output buffer. 434 * @throws ShortBufferException 435 * if the size of the {@code output} buffer is too small. 436 * @throws IllegalBlockSizeException 437 * if the size of the resulting bytes is not a multiple of the 438 * cipher block size. 439 * @throws BadPaddingException 440 * if the padding of the data does not match the padding scheme. 441 * @throws IllegalArgumentException 442 * if the input buffer and the output buffer are the same 443 * object. 444 * @throws IllegalStateException 445 * if this cipher instance is not initialized for encryption or 446 * decryption. 447 */ engineDoFinal(ByteBuffer input, ByteBuffer output)448 protected int engineDoFinal(ByteBuffer input, ByteBuffer output) 449 throws ShortBufferException, IllegalBlockSizeException, 450 BadPaddingException { 451 if (input == null) { 452 throw new NullPointerException("input == null"); 453 } 454 if (output == null) { 455 throw new NullPointerException("output == null"); 456 } 457 int position = input.position(); 458 int limit = input.limit(); 459 460 if ((limit - position) <= 0) { 461 return 0; 462 } 463 byte[] bInput; 464 byte[] bOutput; 465 466 if (input.hasArray()) { 467 bInput = input.array(); 468 int offset = input.arrayOffset(); 469 bOutput = engineDoFinal(bInput, offset + position, limit - position); 470 input.position(limit); 471 } else { 472 bInput = new byte[limit - position]; 473 input.get(bInput); 474 bOutput = engineDoFinal(bInput, 0, limit - position); 475 } 476 if (output.remaining() < bOutput.length) { 477 throw new ShortBufferException("output buffer too small"); 478 } 479 try { 480 output.put(bOutput); 481 } catch (java.nio.BufferOverflowException e) { 482 throw new ShortBufferException("output buffer too small"); 483 } 484 return bOutput.length; 485 } 486 487 /** 488 * Wraps a key using this cipher instance. This method has been added to 489 * this class (for backwards compatibility, it cannot be abstract). If this 490 * method is not overridden, it throws an {@code 491 * UnsupportedOperationException}. 492 * 493 * @param key 494 * the key to wrap. 495 * @return the wrapped key 496 * @throws IllegalBlockSizeException 497 * if the size of the resulting bytes is not a multiple of the 498 * cipher block size. 499 * @throws InvalidKeyException 500 * if this cipher instance cannot wrap this key. 501 */ engineWrap(Key key)502 protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { 503 throw new UnsupportedOperationException(); 504 } 505 506 /** 507 * Unwraps a key using this cipher instance. 508 * <p> 509 * This method has been added to this class (for backwards compatibility, it 510 * cannot be abstract). If this method is not overridden, it throws an 511 * {@code UnsupportedOperationException}. 512 * 513 * @param wrappedKey 514 * the wrapped key to unwrap. 515 * @param wrappedKeyAlgorithm 516 * the algorithm for the wrapped key. 517 * @param wrappedKeyType 518 * the type of the wrapped key (one of: {@code SECRET_KEY}, 519 * {@code PRIVATE_KEY} or {@code PUBLIC_KEY}) 520 * @return the unwrapped key. 521 * @throws InvalidKeyException 522 * if the {@code wrappedKey} cannot be unwrapped to a key of 523 * type {@code wrappedKeyType} for the {@code 524 * wrappedKeyAlgorithm}. 525 * @throws NoSuchAlgorithmException 526 * if no provider can be found that can create a key of type 527 * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. 528 */ engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)529 protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 530 int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { 531 throw new UnsupportedOperationException(); 532 } 533 534 /** 535 * Returns the size of a specified key object in bits. This method has been 536 * added to this class (for backwards compatibility, it cannot be abstract). 537 * If this method is not overridden, it throws an {@code 538 * UnsupportedOperationException}. 539 * 540 * @param key 541 * the key to get the size for. 542 * @return the size of a specified key object in bits. 543 * @throws InvalidKeyException 544 * if the size of the key cannot be determined by this 545 * implementation. 546 */ engineGetKeySize(Key key)547 protected int engineGetKeySize(Key key) throws InvalidKeyException { 548 throw new UnsupportedOperationException(); 549 } 550 } 551