• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (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      */
engineDoFinal(byte[] input, int inputOffset, int inputLen)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      */
engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)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      */
engineDoFinal(ByteBuffer input, ByteBuffer output)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      */
engineWrap(Key key)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      */
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)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      */
engineGetKeySize(Key key)550     protected int engineGetKeySize(Key key) throws InvalidKeyException {
551         throw new UnsupportedOperationException();
552     }
553 }
554