• 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.InvalidParameterException;
25 import java.security.Key;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.NoSuchProviderException;
28 import java.security.Provider;
29 import java.security.Provider.Service;
30 import java.security.ProviderException;
31 import java.security.SecureRandom;
32 import java.security.Security;
33 import java.security.cert.Certificate;
34 import java.security.cert.X509Certificate;
35 import java.security.spec.AlgorithmParameterSpec;
36 import java.util.ArrayList;
37 import java.util.Locale;
38 import java.util.Set;
39 import org.apache.harmony.crypto.internal.NullCipherSpi;
40 import org.apache.harmony.security.fortress.Engine;
41 
42 /**
43  * This class provides access to implementations of cryptographic ciphers for
44  * encryption and decryption. Cipher classes can not be instantiated directly,
45  * one has to call the Cipher's {@code getInstance} method with the name of a
46  * requested transformation, optionally with a provider. A transformation
47  * specifies an operation (or a set of operations) as a string in the form:
48  * <ul>
49  * <li><i>"algorithm/mode/padding"</i></li> or
50  * <li><i>"algorithm"</i></li>
51  * </ul>
52  * <i>algorithm</i> is the name of a cryptographic algorithm, <i>mode</i> is the
53  * name of a feedback mode and <i>padding</i> is the name of a padding scheme.
54  * If <i>mode</i> and/or <i>padding</i> values are omitted, provider specific
55  * default values will be used.
56  * <p>
57  * A valid transformation would be:
58  * <ul>
59  * {@code Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");}
60  * </ul>
61  * When a block cipher is requested in stream cipher mode, the number of bits
62  * to be processed at a time can be optionally specified by appending it to the
63  * mode name. e.g. <i>"AES/CFB8/NoPadding"</i>. If no number is specified, a
64  * provider specific default value is used.
65  */
66 public class Cipher {
67 
68     /**
69      * Constant for decryption operation mode.
70      */
71     public static final int DECRYPT_MODE = 2;
72 
73     /**
74      * Constant for encryption operation mode.
75      */
76     public static final int ENCRYPT_MODE = 1;
77 
78     /**
79      * Constant indicating that the key to be unwrapped is a private key.
80      */
81     public static final int PRIVATE_KEY = 2;
82 
83     /**
84      * Constant indicating that the key to be unwrapped is a public key.
85      */
86     public static final int PUBLIC_KEY = 1;
87 
88     /**
89      * Constant indicating that the key to be unwrapped is a secret key.
90      */
91     public static final int SECRET_KEY = 3;
92 
93     /**
94      * Constant for key unwrapping operation mode.
95      */
96     public static final int UNWRAP_MODE = 4;
97 
98     /**
99      * Constant for key wrapping operation mode.
100      */
101     public static final int WRAP_MODE = 3;
102 
103     private int mode;
104 
105     /** Items that need to be set on the Cipher instance. */
106     private enum NeedToSet {
107         NONE, MODE, PADDING, BOTH,
108     };
109 
110     /**
111      * Used to keep track of which underlying {@code CipherSpi#engineInit(...)}
112      * variant to call when testing suitability.
113      */
114     private static enum InitType {
115         KEY, ALGORITHM_PARAMS, ALGORITHM_PARAM_SPEC,
116     };
117 
118     /**
119      * Keeps track of the possible arguments to {@code Cipher#init(...)}.
120      */
121     private static class InitParams {
122         private final InitType initType;
123         private final int opmode;
124         private final Key key;
125         private final SecureRandom random;
126         private final AlgorithmParameterSpec spec;
127         private final AlgorithmParameters params;
128 
InitParams(InitType initType, int opmode, Key key, SecureRandom random, AlgorithmParameterSpec spec, AlgorithmParameters params)129         private InitParams(InitType initType, int opmode, Key key, SecureRandom random,
130                 AlgorithmParameterSpec spec, AlgorithmParameters params) {
131             this.initType = initType;
132             this.opmode = opmode;
133             this.key = key;
134             this.random = random;
135             this.spec = spec;
136             this.params = params;
137         }
138     }
139 
140     /**
141      * Expresses the various types of transforms that may be used during
142      * initialization.
143      */
144     private static class Transform {
145         private final String name;
146         private final NeedToSet needToSet;
147 
Transform(String name, NeedToSet needToSet)148         public Transform(String name, NeedToSet needToSet) {
149             this.name = name;
150             this.needToSet = needToSet;
151         }
152     }
153 
154     /**
155      * The service name.
156      */
157     private static final String SERVICE = "Cipher";
158 
159     /**
160      * Used to access common engine functionality.
161      */
162     private static final Engine ENGINE = new Engine(SERVICE);
163 
164     /** The attribute used for supported paddings. */
165     private static final String ATTRIBUTE_PADDINGS = "SupportedPaddings";
166 
167     /** The attribute used for supported modes. */
168     private static final String ATTRIBUTE_MODES = "SupportedModes";
169 
170     /**
171      * The provider.
172      */
173     private Provider provider;
174 
175     /**
176      * The provider specified when instance created.
177      */
178     private final Provider specifiedProvider;
179 
180     /**
181      * The SPI implementation.
182      */
183     private CipherSpi spiImpl;
184 
185     /**
186      * The SPI implementation.
187      */
188     private final CipherSpi specifiedSpi;
189 
190     /**
191      * The transformation.
192      */
193     private final String transformation;
194 
195     /**
196      * The transformation split into parts.
197      */
198     private final String[] transformParts;
199 
200     /**
201      * Lock held while the SPI is initializing.
202      */
203     private final Object initLock = new Object();
204 
205     private static SecureRandom secureRandom;
206 
207     /**
208      * Creates a new Cipher instance.
209      *
210      * @param cipherSpi
211      *            the implementation delegate of the cipher.
212      * @param provider
213      *            the provider of the implementation of this cipher.
214      * @param transformation
215      *            the name of the transformation that this cipher performs.
216      * @throws NullPointerException
217      *             if either cipherSpi is {@code null} or provider is {@code
218      *             null} and {@code cipherSpi} is a {@code NullCipherSpi}.
219      */
Cipher(CipherSpi cipherSpi, Provider provider, String transformation)220     protected Cipher(CipherSpi cipherSpi, Provider provider, String transformation) {
221         if (cipherSpi == null) {
222             throw new NullPointerException("cipherSpi == null");
223         }
224         if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
225             throw new NullPointerException("provider == null");
226         }
227         this.specifiedProvider = provider;
228         this.specifiedSpi = cipherSpi;
229         this.transformation = transformation;
230         this.transformParts = null;
231     }
232 
Cipher(String transformation, String[] transformParts, Provider provider)233     private Cipher(String transformation, String[] transformParts, Provider provider) {
234         this.transformation = transformation;
235         this.transformParts = transformParts;
236         this.specifiedProvider = provider;
237         this.specifiedSpi = null;
238     }
239 
240 
241     /**
242      * Creates a new Cipher for the specified transformation. The installed
243      * providers are searched in order for an implementation of the specified
244      * transformation. The first found provider providing the transformation is
245      * used to create the cipher. If no provider is found an exception is
246      * thrown.
247      *
248      * @param transformation
249      *            the name of the transformation to create a cipher for.
250      * @return a cipher for the requested transformation.
251      * @throws NoSuchAlgorithmException
252      *             if no installed provider can provide the
253      *             <i>transformation</i>, or it is {@code null}, empty or in an
254      *             invalid format.
255      * @throws NoSuchPaddingException
256      *             if no installed provider can provide the padding scheme in
257      *             the <i>transformation</i>.
258      */
getInstance(String transformation)259     public static final Cipher getInstance(String transformation)
260             throws NoSuchAlgorithmException, NoSuchPaddingException {
261         return getCipher(transformation, null);
262     }
263 
264     /**
265      * Creates a new cipher for the specified transformation provided by the
266      * specified provider.
267      *
268      * @param transformation
269      *            the name of the transformation to create a cipher for.
270      * @param provider
271      *            the name of the provider to ask for the transformation.
272      * @return a cipher for the requested transformation.
273      * @throws NoSuchAlgorithmException
274      *             if the specified provider can not provide the
275      *             <i>transformation</i>, or it is {@code null}, empty or in an
276      *             invalid format.
277      * @throws NoSuchProviderException
278      *             if no provider with the specified name can be found.
279      * @throws NoSuchPaddingException
280      *             if the requested padding scheme in the <i>transformation</i>
281      *             is not available.
282      * @throws IllegalArgumentException
283      *             if the specified provider is {@code null}.
284      */
getInstance(String transformation, String provider)285     public static final Cipher getInstance(String transformation,
286             String provider) throws NoSuchAlgorithmException,
287             NoSuchProviderException, NoSuchPaddingException {
288 
289         if (provider == null) {
290             throw new IllegalArgumentException("provider == null");
291         }
292 
293         Provider p = Security.getProvider(provider);
294         if (p == null) {
295             throw new NoSuchProviderException("Provider not available: " + provider);
296         }
297         return getInstance(transformation, p);
298     }
299 
300     /**
301      * Creates a new cipher for the specified transformation. The
302      * {@code provider} supplied does not have to be registered.
303      *
304      * @param transformation
305      *            the name of the transformation to create a cipher for.
306      * @param provider
307      *            the provider to ask for the transformation.
308      * @return a cipher for the requested transformation.
309      * @throws NoSuchAlgorithmException
310      *             if the specified provider can not provide the
311      *             <i>transformation</i>, or it is {@code null}, empty or in an
312      *             invalid format.
313      * @throws NoSuchPaddingException
314      *             if the requested padding scheme in the <i>transformation</i>
315      *             is not available.
316      * @throws IllegalArgumentException
317      *             if the provider is {@code null}.
318      */
getInstance(String transformation, Provider provider)319     public static final Cipher getInstance(String transformation,
320             Provider provider) throws NoSuchAlgorithmException,
321             NoSuchPaddingException {
322         if (provider == null) {
323             throw new IllegalArgumentException("provider == null");
324         }
325         return getCipher(transformation, provider);
326     }
327 
invalidTransformation(String transformation)328     private static NoSuchAlgorithmException invalidTransformation(String transformation)
329             throws NoSuchAlgorithmException {
330         throw new NoSuchAlgorithmException("Invalid transformation: " + transformation);
331     }
332 
333     /**
334      * Create a Cipher instance but don't choose a CipherSpi until we have more
335      * information.
336      */
getCipher(String transformation, Provider provider)337     private static Cipher getCipher(String transformation, Provider provider)
338             throws NoSuchAlgorithmException, NoSuchPaddingException {
339         if (transformation == null || transformation.isEmpty()) {
340             throw invalidTransformation(transformation);
341         }
342 
343         String[] transformParts = checkTransformation(transformation);
344 
345         Engine.SpiAndProvider sap;
346         try {
347             sap = tryCombinations(null /* params */, provider, transformation, transformParts);
348         } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
349             // should never happen since we passed in null params
350             throw new ProviderException(e);
351         }
352 
353         if (sap == null) {
354             if (provider == null) {
355                 throw new NoSuchAlgorithmException("No provider found for " + transformation);
356             } else {
357                 throw new NoSuchAlgorithmException("Provider " + provider.getName()
358                         + " does not provide " + transformation);
359             }
360         }
361         return new Cipher(transformation, transformParts, provider);
362     }
363 
364     /**
365      * Checks that the provided algorithm {@code transformation} string is a
366      * valid input. The algorithm is the only mandatory field and input can be
367      * of the form:
368      * <ul>
369      * <li><code>"[cipher]"</code>
370      * <li><code>"[cipher]/[mode]/[padding]"</code>
371      * <li><code>"[cipher]//[padding]"</code>
372      * <li><code>"[cipher]/[mode]"</code>
373      * </ul>
374      * <p>
375      * Returns the specified transformation split up into three parts
376      * corresponding to their function:
377      * <p>
378      * <code>
379      * {&lt;algorithm&gt;, &lt;mode&gt;, &lt;padding&gt;}
380      * </code>
381      * <p>
382      */
checkTransformation(String transformation)383     private static String[] checkTransformation(String transformation)
384             throws NoSuchAlgorithmException {
385         // ignore an extra prefix / characters such as in
386         // "/DES/CBC/PKCS5Padding" http://b/3387688
387         if (transformation.startsWith("/")) {
388             transformation = transformation.substring(1);
389         }
390         // 'transformation' should be of the form "algorithm/mode/padding".
391         String[] pieces = transformation.split("/");
392         if (pieces.length > 3) {
393             throw invalidTransformation(transformation);
394         }
395         // Empty or missing pieces are represented by null.
396         String[] result = new String[3];
397         for (int i = 0; i < pieces.length; ++i) {
398             String piece = pieces[i].trim();
399             if (!piece.isEmpty()) {
400                 result[i] = piece;
401             }
402         }
403         // You MUST specify an algorithm.
404         if (result[0] == null) {
405             throw invalidTransformation(transformation);
406         }
407         if (!(result[1] == null && result[2] == null) && (result[1] == null || result[2] == null)) {
408             throw invalidTransformation(transformation);
409         }
410         return result;
411     }
412 
413     /**
414      * Makes sure a CipherSpi that matches this type is selected. If
415      * {@code key != null} then it assumes that a suitable provider exists for
416      * this instance (used by {@link #init}. If the {@code initParams} is passed
417      * in, then the {@code CipherSpi} returned will be initialized.
418      *
419      * @throws InvalidKeyException if the specified key cannot be used to
420      *             initialize this cipher.
421      * @throws InvalidAlgorithmParameterException
422      */
getSpi(InitParams initParams)423     private CipherSpi getSpi(InitParams initParams) throws InvalidKeyException,
424             InvalidAlgorithmParameterException {
425         if (specifiedSpi != null) {
426             return specifiedSpi;
427         }
428 
429         synchronized (initLock) {
430             // This is not only a matter of performance. Many methods like update, doFinal, etc.
431             // call {@code #getSpi()} (ie, {@code #getSpi(null /* params */)}) and without this
432             // shortcut they would override an spi that was chosen using the key.
433             if (spiImpl != null && initParams == null) {
434                 return spiImpl;
435             }
436 
437             final Engine.SpiAndProvider sap = tryCombinations(initParams, specifiedProvider,
438                     transformation, transformParts);
439             if (sap == null) {
440                 throw new ProviderException("No provider found for " + transformation);
441             }
442 
443             spiImpl = (CipherSpi) sap.spi;
444             provider = sap.provider;
445 
446             return spiImpl;
447         }
448     }
449 
450     /**
451      * Convenience call when the Key is not available.
452      */
getSpi()453     private CipherSpi getSpi() {
454         try {
455             return getSpi(null);
456         } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
457             throw new ProviderException("Exception thrown when params == null", e);
458         }
459     }
460 
461     /**
462      * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no
463      * {@code CipherSpi} is backing this {@code Cipher}.
464      *
465      * @hide
466      */
getCurrentSpi()467     public CipherSpi getCurrentSpi() {
468         if (specifiedSpi != null) {
469             return specifiedSpi;
470         }
471 
472         synchronized (initLock) {
473             return spiImpl;
474         }
475     }
476 
477     /**
478      * Tries to find the correct {@code Cipher} transform to use. Returns a
479      * {@link Engine.SpiAndProvider}, throws the first exception that was
480      * encountered during attempted initialization, or {@code null} if there are
481      * no providers that support the {@code initParams}.
482      * <p>
483      * {@code transformParts} must be in the format returned by
484      * {@link #checkTransformation(String)}. The combinations of mode strings
485      * tried are as follows:
486      * <ul>
487      * <li><code>[cipher]/[mode]/[padding]</code>
488      * <li><code>[cipher]/[mode]</code>
489      * <li><code>[cipher]//[padding]</code>
490      * <li><code>[cipher]</code>
491      * </ul>
492      */
tryCombinations(InitParams initParams, Provider provider, String transformation, String[] transformParts)493     private static Engine.SpiAndProvider tryCombinations(InitParams initParams, Provider provider,
494             String transformation, String[] transformParts) throws InvalidKeyException,
495             InvalidAlgorithmParameterException {
496         // Enumerate all the transforms we need to try
497         ArrayList<Transform> transforms = new ArrayList<Transform>();
498         if (transformParts[1] != null && transformParts[2] != null) {
499             transforms.add(new Transform(transformParts[0] + "/" + transformParts[1] + "/"
500                     + transformParts[2], NeedToSet.NONE));
501         }
502         if (transformParts[1] != null) {
503             transforms.add(new Transform(transformParts[0] + "/" + transformParts[1],
504                     NeedToSet.PADDING));
505         }
506         if (transformParts[2] != null) {
507             transforms.add(new Transform(transformParts[0] + "//" + transformParts[2],
508                     NeedToSet.MODE));
509         }
510         transforms.add(new Transform(transformParts[0], NeedToSet.BOTH));
511 
512         // Try each of the transforms and keep track of the first exception
513         // encountered.
514         Exception cause = null;
515         for (Transform transform : transforms) {
516             if (provider != null) {
517                 Provider.Service service = provider.getService(SERVICE, transform.name);
518                 if (service == null) {
519                     continue;
520                 }
521                 return tryTransformWithProvider(initParams, transformParts, transform.needToSet,
522                         service);
523             }
524             ArrayList<Provider.Service> services = ENGINE.getServices(transform.name);
525             if (services == null || services.isEmpty()) {
526                 continue;
527             }
528             for (Provider.Service service : services) {
529                 if (initParams == null || initParams.key == null
530                         || service.supportsParameter(initParams.key)) {
531                     try {
532                         Engine.SpiAndProvider sap = tryTransformWithProvider(initParams,
533                                 transformParts, transform.needToSet, service);
534                         if (sap != null) {
535                             return sap;
536                         }
537                     } catch (Exception e) {
538                         if (cause == null) {
539                             cause = e;
540                         }
541                     }
542                 }
543             }
544         }
545         if (cause instanceof InvalidKeyException) {
546             throw (InvalidKeyException) cause;
547         } else if (cause instanceof InvalidAlgorithmParameterException) {
548             throw (InvalidAlgorithmParameterException) cause;
549         } else if (cause instanceof RuntimeException) {
550             throw (RuntimeException) cause;
551         } else if (cause != null) {
552             throw new InvalidKeyException("No provider can be initialized with given key", cause);
553         } else if (initParams == null || initParams.key == null) {
554             return null;
555         } else {
556             // Since the key is not null, a suitable provider exists,
557             // and it is an InvalidKeyException.
558             throw new InvalidKeyException("No provider offers " + transformation + " for "
559                     + initParams.key.getAlgorithm() + " key of class "
560                     + initParams.key.getClass().getName() + " and export format "
561                     + initParams.key.getFormat());
562         }
563     }
564 
565     /**
566      * Tries to initialize the {@code Cipher} from a given {@code service}. If
567      * initialization is successful, the initialized {@code spi} is returned. If
568      * the {@code service} cannot be initialized with the specified
569      * {@code initParams}, then it's expected to throw
570      * {@code InvalidKeyException} or {@code InvalidAlgorithmParameterException}
571      * as a hint to the caller that it should continue searching for a
572      * {@code Service} that will work.
573      */
tryTransformWithProvider(InitParams initParams, String[] transformParts, NeedToSet type, Provider.Service service)574     private static Engine.SpiAndProvider tryTransformWithProvider(InitParams initParams,
575             String[] transformParts, NeedToSet type, Provider.Service service)
576             throws InvalidKeyException, InvalidAlgorithmParameterException {
577         try {
578             /*
579              * Check to see if the Cipher even supports the attributes before
580              * trying to instantiate it.
581              */
582             if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1])
583                     || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) {
584                 return null;
585             }
586 
587             Engine.SpiAndProvider sap = ENGINE.getInstance(service, null);
588             if (sap.spi == null || sap.provider == null) {
589                 return null;
590             }
591             CipherSpi spi = (CipherSpi) sap.spi;
592             if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH))
593                     && (transformParts[1] != null)) {
594                 spi.engineSetMode(transformParts[1]);
595             }
596             if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH))
597                     && (transformParts[2] != null)) {
598                 spi.engineSetPadding(transformParts[2]);
599             }
600 
601             if (initParams != null) {
602                 switch (initParams.initType) {
603                     case ALGORITHM_PARAMS:
604                         spi.engineInit(initParams.opmode, initParams.key, initParams.params,
605                                 initParams.random);
606                         break;
607                     case ALGORITHM_PARAM_SPEC:
608                         spi.engineInit(initParams.opmode, initParams.key, initParams.spec,
609                                 initParams.random);
610                         break;
611                     case KEY:
612                         spi.engineInit(initParams.opmode, initParams.key, initParams.random);
613                         break;
614                     default:
615                         throw new AssertionError("This should never be reached");
616                 }
617             }
618             return sap;
619         } catch (NoSuchAlgorithmException ignored) {
620         } catch (NoSuchPaddingException ignored) {
621         }
622         return null;
623     }
624 
625     /**
626      * If the attribute listed exists, check that it matches the regular
627      * expression.
628      */
matchAttribute(Service service, String attr, String value)629     private static boolean matchAttribute(Service service, String attr, String value) {
630         if (value == null) {
631             return true;
632         }
633         final String pattern = service.getAttribute(attr);
634         if (pattern == null) {
635             return true;
636         }
637         final String valueUc = value.toUpperCase(Locale.US);
638         return valueUc.matches(pattern.toUpperCase(Locale.US));
639     }
640 
641     /**
642      * Returns the provider of this cipher instance.
643      *
644      * @return the provider of this cipher instance.
645      */
getProvider()646     public final Provider getProvider() {
647         getSpi();
648         return provider;
649     }
650 
651     /**
652      * Returns the name of the algorithm of this cipher instance.
653      * <p>
654      * This is the name of the <i>transformation</i> argument used in the
655      * {@code getInstance} call creating this object.
656      *
657      * @return the name of the algorithm of this cipher instance.
658      */
getAlgorithm()659     public final String getAlgorithm() {
660         return transformation;
661     }
662 
663     /**
664      * Returns this ciphers block size (in bytes).
665      *
666      * @return this ciphers block size.
667      */
getBlockSize()668     public final int getBlockSize() {
669         return getSpi().engineGetBlockSize();
670     }
671 
672     /**
673      * Returns the length in bytes an output buffer needs to be when this cipher
674      * is updated with {@code inputLen} bytes.
675      *
676      * @param inputLen
677      *            the number of bytes of the input.
678      * @return the output buffer length for the input length.
679      * @throws IllegalStateException
680      *             if this cipher instance is in an invalid state.
681      */
getOutputSize(int inputLen)682     public final int getOutputSize(int inputLen) {
683         if (mode == 0) {
684             throw new IllegalStateException("Cipher has not yet been initialized");
685         }
686         return getSpi().engineGetOutputSize(inputLen);
687     }
688 
689     /**
690      * Returns the <i>initialization vector</i> for this cipher instance.
691      *
692      * @return the <i>initialization vector</i> for this cipher instance.
693      */
getIV()694     public final byte[] getIV() {
695         return getSpi().engineGetIV();
696     }
697 
698     /**
699      * Returns the parameters that where used to create this cipher instance.
700      * <p>
701      * These may be a the same parameters that were used to create this cipher
702      * instance, or may be a combination of default and random parameters,
703      * depending on the underlying cipher implementation.
704      *
705      * @return the parameters that where used to create this cipher instance, or
706      *         {@code null} if this cipher instance does not have any
707      *         parameters.
708      */
getParameters()709     public final AlgorithmParameters getParameters() {
710         return getSpi().engineGetParameters();
711     }
712 
713     /**
714      * Returns the exemption mechanism associated with this cipher.
715      *
716      * @return currently {@code null}
717      */
getExemptionMechanism()718     public final ExemptionMechanism getExemptionMechanism() {
719         //FIXME implement getExemptionMechanism
720 
721         //        try {
722         //            return ExemptionMechanism.getInstance(transformation, provider);
723         //        } catch (NoSuchAlgorithmException e) {
724         return null;
725         //        }
726 
727     }
728 
729     /**
730      * Checks that the provided {@code mode} is one that is valid for
731      * {@code Cipher}.
732      */
checkMode(int mode)733     private void checkMode(int mode) {
734         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE && mode != UNWRAP_MODE
735                 && mode != WRAP_MODE) {
736             throw new InvalidParameterException("Invalid mode: " + mode);
737         }
738     }
739 
740     /**
741      * Initializes this cipher instance with the specified key.
742      * <p>
743      * The cipher is initialized for the specified operational mode (one of:
744      * encryption, decryption, key wrapping or key unwrapping) depending on
745      * {@code opmode}.
746      * <p>
747      * If this cipher instance needs any algorithm parameters or random values
748      * that the specified key can not provide, the underlying implementation of
749      * this cipher is supposed to generate the required parameters (using its
750      * provider or random values).
751      * <p>
752      * When a cipher instance is initialized by a call to any of the {@code
753      * init} methods, the state of the instance is overridden, meaning that it
754      * is equivalent to creating a new instance and calling its {@code init}
755      * method.
756      *
757      * @param opmode
758      *            the operation this cipher instance should be initialized for
759      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
760      *            WRAP_MODE} or {@code UNWRAP_MODE}).
761      * @param key
762      *            the input key for the operation.
763      * @throws InvalidKeyException
764      *             if the specified key can not be used to initialize this
765      *             cipher instance.
766      */
init(int opmode, Key key)767     public final void init(int opmode, Key key) throws InvalidKeyException {
768         if (secureRandom == null) {
769             // In theory it might be thread-unsafe but in the given case it's OK
770             // since it does not matter which SecureRandom instance is passed
771             // to the init()
772             secureRandom = new SecureRandom();
773         }
774         init(opmode, key, secureRandom);
775     }
776 
777     /**
778      * Initializes this cipher instance with the specified key and a source of
779      * randomness.
780      * <p>
781      * The cipher is initialized for the specified operational mode (one of:
782      * encryption, decryption, key wrapping or key unwrapping) depending on
783      * {@code opmode}.
784      * <p>
785      * If this cipher instance needs any algorithm parameters or random values
786      * that the specified key can not provide, the underlying implementation of
787      * this cipher is supposed to generate the required parameters (using its
788      * provider or random values). Random values are generated using {@code
789      * random};
790      * <p>
791      * When a cipher instance is initialized by a call to any of the {@code
792      * init} methods, the state of the instance is overridden, means it is
793      * equivalent to creating a new instance and calling it {@code init} method.
794      *
795      * @param opmode
796      *            the operation this cipher instance should be initialized for
797      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
798      *            WRAP_MODE} or {@code UNWRAP_MODE}).
799      * @param key
800      *            the input key for the operation.
801      * @param random
802      *            the source of randomness to use.
803      * @throws InvalidKeyException
804      *             if the specified key can not be used to initialize this
805      *             cipher instance.
806      * @throws InvalidParameterException
807      *             if the specified opmode is invalid.
808      */
init(int opmode, Key key, SecureRandom random)809     public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
810         checkMode(opmode);
811         //        FIXME InvalidKeyException
812         //        if keysize exceeds the maximum allowable keysize
813         //        (jurisdiction policy files)
814         try {
815             getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null));
816         } catch (InvalidAlgorithmParameterException e) {
817             // Should never happen since we only specified the key.
818             throw new ProviderException("Invalid parameters when params == null", e);
819         }
820         mode = opmode;
821     }
822 
823     /**
824      * Initializes this cipher instance with the specified key and algorithm
825      * parameters.
826      * <p>
827      * The cipher is initialized for the specified operational mode (one of:
828      * encryption, decryption, key wrapping or key unwrapping).
829      * <p>
830      * If this cipher instance needs any algorithm parameters and {@code params}
831      * is {@code null}, the underlying implementation of this cipher is supposed
832      * to generate the required parameters (using its provider or random
833      * values).
834      * <p>
835      * When a cipher instance is initialized by a call to any of the {@code
836      * init} methods, the state of the instance is overridden, means it is
837      * equivalent to creating a new instance and calling it {@code init} method.
838      *
839      * @param opmode
840      *            the operation this cipher instance should be initialized for
841      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
842      *            WRAP_MODE} or {@code UNWRAP_MODE}).
843      * @param key
844      *            the input key for the operation.
845      * @param params
846      *            the algorithm parameters.
847      * @throws InvalidKeyException
848      *             if the specified key can not be used to initialize this
849      *             cipher instance.
850      * @throws InvalidAlgorithmParameterException
851      *             it the specified parameters are inappropriate for this
852      *             cipher.
853      */
init(int opmode, Key key, AlgorithmParameterSpec params)854     public final void init(int opmode, Key key, AlgorithmParameterSpec params)
855             throws InvalidKeyException, InvalidAlgorithmParameterException {
856         if (secureRandom == null) {
857             secureRandom = new SecureRandom();
858         }
859         init(opmode, key, params, secureRandom);
860     }
861 
862     /**
863      * Initializes this cipher instance with the specified key, algorithm
864      * parameters and a source of randomness.
865      * <p>
866      * The cipher is initialized for the specified operational mode (one of:
867      * encryption, decryption, key wrapping or key unwrapping) depending on
868      * {@code opmode}.
869      * <p>
870      * If this cipher instance needs any algorithm parameters and {@code params}
871      * is {@code null}, the underlying implementation of this cipher is supposed
872      * to generate the required parameters (using its provider or random
873      * values). Random values are generated using {@code random};
874      * <p>
875      * When a cipher instance is initialized by a call to any of the {@code
876      * init} methods, the state of the instance is overridden, meaning that it
877      * is equivalent to creating a new instance and calling it {@code init}
878      * method.
879      *
880      * @param opmode
881      *            the operation this cipher instance should be initialized for
882      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
883      *            WRAP_MODE} or {@code UNWRAP_MODE}).
884      * @param key
885      *            the input key for the operation.
886      * @param params
887      *            the algorithm parameters.
888      * @param random
889      *            the source of randomness to use.
890      * @throws InvalidKeyException
891      *             if the specified key can not be used to initialize this
892      *             cipher instance.
893      * @throws InvalidAlgorithmParameterException
894      *             it the specified parameters are inappropriate for this
895      *             cipher.
896      * @throws InvalidParameterException
897      *             if the specified {@code opmode} is invalid.
898      */
init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)899     public final void init(int opmode, Key key, AlgorithmParameterSpec params,
900             SecureRandom random) throws InvalidKeyException,
901             InvalidAlgorithmParameterException {
902         checkMode(opmode);
903         //        FIXME InvalidKeyException
904         //        if keysize exceeds the maximum allowable keysize
905         //        (jurisdiction policy files)
906         //        FIXME InvalidAlgorithmParameterException
907         //        cryptographic strength exceed the legal limits
908         //        (jurisdiction policy files)
909         getSpi(new InitParams(InitType.ALGORITHM_PARAM_SPEC, opmode, key, random, params, null));
910         mode = opmode;
911     }
912 
913     /**
914      * Initializes this cipher instance with the specified key and algorithm
915      * parameters.
916      * <p>
917      * The cipher is initialized for the specified operation (one of:
918      * encryption, decryption, key wrapping or key unwrapping) depending on
919      * {@code opmode}.
920      * <p>
921      * If this cipher instance needs any algorithm parameters and {@code params}
922      * is {@code null}, the underlying implementation of this cipher is supposed
923      * to generate the required parameters (using its provider or random
924      * values).
925      * <p>
926      * When a cipher instance is initialized by a call to any of the {@code
927      * init} methods, the state of the instance is overridden, meaning that it
928      * is equivalent to creating a new instance and calling it {@code init}
929      * method.
930      *
931      * @param opmode
932      *            the operation this cipher instance should be initialized for
933      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
934      *            WRAP_MODE} or {@code UNWRAP_MODE}).
935      * @param key
936      *            the input key for the operation.
937      * @param params
938      *            the algorithm parameters.
939      * @throws InvalidKeyException
940      *             if the specified key can not be used to initialize this
941      *             cipher instance.
942      * @throws InvalidAlgorithmParameterException
943      *             it the specified parameters are inappropriate for this
944      *             cipher.
945      */
init(int opmode, Key key, AlgorithmParameters params)946     public final void init(int opmode, Key key, AlgorithmParameters params)
947             throws InvalidKeyException, InvalidAlgorithmParameterException {
948         if (secureRandom == null) {
949             secureRandom = new SecureRandom();
950         }
951         init(opmode, key, params, secureRandom);
952     }
953 
954     /**
955      * Initializes this cipher instance with the specified key, algorithm
956      * parameters and a source of randomness.
957      * <p>
958      * The cipher will be initialized for the specified operation (one of:
959      * encryption, decryption, key wrapping or key unwrapping) depending on
960      * {@code opmode}.
961      * <p>
962      * If this cipher instance needs any algorithm parameters and {@code params}
963      * is {@code null}, the underlying implementation of this cipher is supposed
964      * to generate the required parameters (using its provider or random
965      * values). Random values are generated using {@code random}.
966      * <p>
967      * When a cipher instance is initialized by a call to any of the {@code
968      * init} methods, the state of the instance is overridden, means it is
969      * equivalent to creating a new instance and calling it {@code init} method.
970      *
971      * @param opmode
972      *            the operation this cipher instance should be initialized for
973      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
974      *            WRAP_MODE} or {@code UNWRAP_MODE}).
975      * @param key
976      *            the input key for the operation.
977      * @param params
978      *            the algorithm parameters.
979      * @param random
980      *            the source of randomness to use.
981      * @throws InvalidKeyException
982      *             if the specified key can not be used to initialize this
983      *             cipher instance.
984      * @throws InvalidAlgorithmParameterException
985      *             if the specified parameters are inappropriate for this
986      *             cipher.
987      * @throws InvalidParameterException
988      *             if the specified {@code opmode} is invalid.
989      */
init(int opmode, Key key, AlgorithmParameters params, SecureRandom random)990     public final void init(int opmode, Key key, AlgorithmParameters params,
991             SecureRandom random) throws InvalidKeyException,
992             InvalidAlgorithmParameterException {
993         checkMode(opmode);
994         //        FIXME InvalidKeyException
995         //        if keysize exceeds the maximum allowable keysize
996         //        (jurisdiction policy files)
997         //        FIXME InvalidAlgorithmParameterException
998         //        cryptographic strength exceed the legal limits
999         //        (jurisdiction policy files)
1000         getSpi(new InitParams(InitType.ALGORITHM_PARAMS, opmode, key, random, null, params));
1001         mode = opmode;
1002     }
1003 
1004     /**
1005      * Initializes this cipher instance with the public key from the specified
1006      * certificate.
1007      * <p>
1008      * The cipher will be initialized for the specified operation (one of:
1009      * encryption, decryption, key wrapping or key unwrapping) depending on
1010      * {@code opmode}.
1011      * <p>
1012      * It the type of the certificate is X.509 and the certificate has a <i>key
1013      * usage</i> extension field marked as critical, the specified {@code
1014      * opmode} has the be enabled for this key, otherwise an {@code
1015      * InvalidKeyException} is thrown.
1016      * <p>
1017      * If this cipher instance needs any algorithm parameters that the key in
1018      * the certificate can not provide, the underlying implementation of this
1019      * cipher is supposed to generate the required parameters (using its
1020      * provider or random values).
1021      * <p>
1022      * When a cipher instance is initialized by a call to any of the {@code
1023      * init} methods, the state of the instance is overridden, means it is
1024      * equivalent to creating a new instance and calling it {@code init} method.
1025      *
1026      * @param opmode
1027      *            the operation this cipher instance should be initialized for
1028      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
1029      *            WRAP_MODE} or {@code UNWRAP_MODE}).
1030      * @param certificate
1031      *            the certificate.
1032      * @throws InvalidKeyException
1033      *             if the public key in the certificate can not be used to
1034      *             initialize this cipher instance.
1035      */
init(int opmode, Certificate certificate)1036     public final void init(int opmode, Certificate certificate)
1037             throws InvalidKeyException {
1038         if (secureRandom == null) {
1039             secureRandom = new SecureRandom();
1040         }
1041         init(opmode, certificate, secureRandom);
1042     }
1043 
1044     /**
1045      * Initializes this cipher instance with the public key from the specified
1046      * certificate and a source of randomness.
1047      * <p>
1048      * The cipher will be initialized for the specified operation (one of:
1049      * encryption, decryption, key wrapping or key unwrapping) depending on
1050      * {@code opmode}.
1051      * <p>
1052      * It the type of the certificate is X.509 and the certificate has a <i>key
1053      * usage</i> extension field marked as critical, the specified {@code
1054      * opmode} has the be enabled for this key, otherwise an {@code
1055      * InvalidKeyException} is thrown.
1056      * <p>
1057      * If this cipher instance needs any algorithm parameters that the key in
1058      * the certificate can not provide, the underlying implementation of this
1059      * cipher is supposed to generate the required parameters (using its
1060      * provider or random values). Random values are generated using {@code
1061      * random}.
1062      * <p>
1063      * When a cipher instance is initialized by a call to any of the {@code
1064      * init} methods, the state of the instance is overridden, means it is
1065      * equivalent to creating a new instance and calling it {@code init} method.
1066      *
1067      * @param opmode
1068      *            the operation this cipher instance should be initialized for
1069      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
1070      *            WRAP_MODE} or {@code UNWRAP_MODE}).
1071      * @param certificate
1072      *            the certificate.
1073      * @param random
1074      *            the source of randomness to be used.
1075      * @throws InvalidKeyException
1076      *             if the public key in the certificate can not be used to
1077      *             initialize this cipher instance.
1078      */
init(int opmode, Certificate certificate, SecureRandom random)1079     public final void init(int opmode, Certificate certificate,
1080             SecureRandom random) throws InvalidKeyException {
1081         checkMode(opmode);
1082         if (certificate instanceof X509Certificate) {
1083             Set<String> ce = ((X509Certificate) certificate).getCriticalExtensionOIDs();
1084             boolean critical = false;
1085             if (ce != null && !ce.isEmpty()) {
1086                 for (String oid : ce) {
1087                     if (oid.equals("2.5.29.15")) { // KeyUsage OID = 2.5.29.15
1088                         critical = true;
1089                         break;
1090                     }
1091                 }
1092                 if (critical) {
1093                     boolean[] keyUsage = ((X509Certificate) certificate).getKeyUsage();
1094                     // As specified in RFC 3280:
1095                     //   Internet X.509 Public Key Infrastructure
1096                     //   Certificate and Certificate Revocation List (CRL) Profile.
1097                     // Section 4.2.1.3  Key Usage
1098                     // http://www.ietf.org/rfc/rfc3280.txt
1099                     //
1100                     // KeyUsage ::= BIT STRING {digitalSignature (0),
1101                     //                          nonRepudiation   (1),
1102                     //                          keyEncipherment  (2),
1103                     //                          dataEncipherment (3),
1104                     //                          keyAgreement     (4),
1105                     //                          keyCertSign      (5),
1106                     //                          cRLSign          (6),
1107                     //                          encipherOnly     (7),
1108                     //                          decipherOnly     (8) }
1109                     if (keyUsage != null) {
1110                         if (opmode == ENCRYPT_MODE && !keyUsage[3]) {
1111                             throw new InvalidKeyException("The public key in the certificate "
1112                                                           + "cannot be used for ENCRYPT_MODE");
1113                         } else if (opmode == WRAP_MODE && !keyUsage[2]) {
1114                             throw new InvalidKeyException("The public key in the certificate "
1115                                                           + "cannot be used for WRAP_MODE");
1116                         }
1117                     }
1118                 }
1119             }
1120         }
1121         //        FIXME InvalidKeyException
1122         //        if keysize exceeds the maximum allowable keysize
1123         //        (jurisdiction policy files)
1124         final Key key = certificate.getPublicKey();
1125         try {
1126             getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null));
1127         } catch (InvalidAlgorithmParameterException e) {
1128             // Should never happen since we only specified the key.
1129             throw new ProviderException("Invalid parameters when params == null", e);
1130         }
1131         mode = opmode;
1132     }
1133 
1134     /**
1135      * Continues a multi-part transformation (encryption or decryption). The
1136      * transformed bytes are returned.
1137      *
1138      * @param input
1139      *            the input bytes to transform.
1140      * @return the transformed bytes in a new buffer, or {@code null} if the
1141      *         input has zero length.
1142      * @throws IllegalStateException
1143      *             if this cipher instance is not initialized for encryption or
1144      *             decryption.
1145      * @throws IllegalArgumentException
1146      *             if the input is {@code null}.
1147      */
update(byte[] input)1148     public final byte[] update(byte[] input) {
1149         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1150             throw new IllegalStateException();
1151         }
1152         if (input == null) {
1153             throw new IllegalArgumentException("input == null");
1154         }
1155         if (input.length == 0) {
1156             return null;
1157         }
1158         return getSpi().engineUpdate(input, 0, input.length);
1159     }
1160 
1161     /**
1162      * Continues a multi-part transformation (encryption or decryption). The
1163      * transformed bytes are returned.
1164      *
1165      * @param input
1166      *            the input bytes to transform.
1167      * @param inputOffset
1168      *            the offset in the input to start.
1169      * @param inputLen
1170      *            the length of the input to transform.
1171      * @return the transformed bytes in a new buffer, or {@code null} if {@code inputLen} is zero.
1172      * @throws IllegalStateException
1173      *             if this cipher instance is not initialized for encryption or
1174      *             decryption.
1175      * @throws IllegalArgumentException
1176      *             if {@code input} is {@code null}, or if {@code inputOffset} and
1177      *             {@code inputLen} do not specify a valid chunk in the input
1178      *             buffer.
1179      */
update(byte[] input, int inputOffset, int inputLen)1180     public final byte[] update(byte[] input, int inputOffset, int inputLen) {
1181         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1182             throw new IllegalStateException();
1183         }
1184         if (input == null) {
1185             throw new IllegalArgumentException("input == null");
1186         }
1187         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1188         if (inputLen == 0) {
1189             return null;
1190         }
1191         return getSpi().engineUpdate(input, inputOffset, inputLen);
1192     }
1193 
checkInputOffsetAndCount(int inputArrayLength, int inputOffset, int inputLen)1194     private static void checkInputOffsetAndCount(int inputArrayLength,
1195                                                  int inputOffset,
1196                                                  int inputLen) {
1197         if ((inputOffset | inputLen) < 0
1198                 || inputOffset > inputArrayLength
1199                 || inputArrayLength - inputOffset < inputLen) {
1200             throw new IllegalArgumentException("input.length=" + inputArrayLength
1201                                                + "; inputOffset=" + inputOffset
1202                                                + "; inputLen=" + inputLen);
1203         }
1204     }
1205 
1206     /**
1207      * Continues a multi-part transformation (encryption or decryption). The
1208      * transformed bytes are stored in the {@code output} buffer.
1209      * <p>
1210      * If the size of the {@code output} buffer is too small to hold the result,
1211      * a {@code ShortBufferException} is thrown. Use
1212      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
1213      * output buffer.
1214      *
1215      * @param input
1216      *            the input bytes to transform.
1217      * @param inputOffset
1218      *            the offset in the input to start.
1219      * @param inputLen
1220      *            the length of the input to transform.
1221      * @param output
1222      *            the output buffer.
1223      * @return the number of bytes placed in output.
1224      * @throws ShortBufferException
1225      *             if the size of the {@code output} buffer is too small.
1226      * @throws IllegalStateException
1227      *             if this cipher instance is not initialized for encryption or
1228      *             decryption.
1229      * @throws IllegalArgumentException
1230      *             if the input is {@code null}, the output is {@code null}, or
1231      *             if {@code inputOffset} and {@code inputLen} do not specify a
1232      *             valid chunk in the input buffer.
1233      */
update(byte[] input, int inputOffset, int inputLen, byte[] output)1234     public final int update(byte[] input, int inputOffset, int inputLen,
1235             byte[] output) throws ShortBufferException {
1236         return update(input, inputOffset, inputLen, output, 0);
1237     }
1238 
1239     /**
1240      * Continues a multi-part transformation (encryption or decryption). The
1241      * transformed bytes are stored in the {@code output} buffer.
1242      * <p>
1243      * If the size of the {@code output} buffer is too small to hold the result,
1244      * a {@code ShortBufferException} is thrown. Use
1245      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
1246      * output buffer.
1247      *
1248      * @param input
1249      *            the input bytes to transform.
1250      * @param inputOffset
1251      *            the offset in the input to start.
1252      * @param inputLen
1253      *            the length of the input to transform.
1254      * @param output
1255      *            the output buffer.
1256      * @param outputOffset
1257      *            the offset in the output buffer.
1258      * @return the number of bytes placed in output.
1259      * @throws ShortBufferException
1260      *             if the size of the {@code output} buffer is too small.
1261      * @throws IllegalStateException
1262      *             if this cipher instance is not initialized for encryption or
1263      *             decryption.
1264      * @throws IllegalArgumentException
1265      *             if the input is {@code null}, the output is {@code null}, or
1266      *             if {@code inputOffset} and {@code inputLen} do not specify a
1267      *             valid chunk in the input buffer.
1268      */
update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1269     public final int update(byte[] input, int inputOffset, int inputLen,
1270             byte[] output, int outputOffset) throws ShortBufferException {
1271         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1272             throw new IllegalStateException();
1273         }
1274         if (input == null) {
1275             throw new IllegalArgumentException("input == null");
1276         }
1277         if (output == null) {
1278             throw new IllegalArgumentException("output == null");
1279         }
1280         if (outputOffset < 0) {
1281             throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
1282         }
1283         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1284         if (input.length == 0) {
1285             return 0;
1286         }
1287         return getSpi().engineUpdate(input, inputOffset, inputLen, output,
1288                 outputOffset);
1289     }
1290 
1291     /**
1292      * Continues a multi-part transformation (encryption or decryption). The
1293      * {@code input.remaining()} bytes starting at {@code input.position()} are
1294      * transformed and stored in the {@code output} buffer.
1295      * <p>
1296      * If the {@code output.remaining()} is too small to hold the transformed
1297      * bytes a {@code ShortBufferException} is thrown. Use
1298      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
1299      * output buffer.
1300      *
1301      * @param input
1302      *            the input buffer to transform.
1303      * @param output
1304      *            the output buffer to store the result within.
1305      * @return the number of bytes stored in the output buffer.
1306      * @throws ShortBufferException
1307      *             if the size of the {@code output} buffer is too small.
1308      * @throws IllegalStateException
1309      *             if this cipher instance is not initialized for encryption or
1310      *             decryption.
1311      * @throws IllegalArgumentException
1312      *             if the input buffer and the output buffer are the identical
1313      *             object.
1314      */
update(ByteBuffer input, ByteBuffer output)1315     public final int update(ByteBuffer input, ByteBuffer output)
1316             throws ShortBufferException {
1317         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1318             throw new IllegalStateException();
1319         }
1320         if (input == output) {
1321             throw new IllegalArgumentException("input == output");
1322         }
1323         return getSpi().engineUpdate(input, output);
1324     }
1325 
1326     /**
1327      * Continues a multi-part transformation (encryption or decryption) with
1328      * Authenticated Additional Data (AAD). AAD may only be added after the
1329      * {@code Cipher} is initialized and before any data is passed to the
1330      * instance.
1331      * <p>
1332      * This is only usable with cipher modes that support Authenticated
1333      * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM).
1334      *
1335      * @param input bytes of AAD to use with the cipher
1336      * @throws IllegalStateException
1337      *             if this cipher instance is not initialized for encryption or
1338      *             decryption.
1339      * @throws IllegalArgumentException
1340      *             if {@code input} is {@code null}
1341      * @throws UnsupportedOperationException if the cipher does not support AEAD
1342      * @since 1.7
1343      */
updateAAD(byte[] input)1344     public final void updateAAD(byte[] input) {
1345         if (input == null) {
1346             throw new IllegalArgumentException("input == null");
1347         }
1348         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1349             throw new IllegalStateException();
1350         }
1351         if (input.length == 0) {
1352             return;
1353         }
1354         getSpi().engineUpdateAAD(input, 0, input.length);
1355     }
1356 
1357     /**
1358      * Continues a multi-part transformation (encryption or decryption) with
1359      * Authenticated Additional Data (AAD). AAD may only be added after the
1360      * {@code Cipher} is initialized and before any data is passed to the
1361      * instance.
1362      * <p>
1363      * This is only usable with cipher modes that support Authenticated
1364      * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM).
1365      *
1366      * @param input bytes of AAD to use with the cipher
1367      * @param inputOffset offset within bytes of additional data to add to cipher
1368      * @param inputLen length of bytes of additional data to add to cipher
1369      * @throws IllegalStateException
1370      *             if this cipher instance is not initialized for encryption or
1371      *             decryption.
1372      * @throws IllegalArgumentException
1373      *             if {@code input} is {@code null}, or if {@code inputOffset} and
1374      *             {@code inputLen} do not specify a valid chunk in the input
1375      *             buffer.
1376      * @throws UnsupportedOperationException if the cipher does not support AEAD
1377      * @since 1.7
1378      */
updateAAD(byte[] input, int inputOffset, int inputLen)1379     public final void updateAAD(byte[] input, int inputOffset, int inputLen) {
1380         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1381             throw new IllegalStateException();
1382         }
1383         if (input == null) {
1384             throw new IllegalArgumentException("input == null");
1385         }
1386         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1387         if (input.length == 0) {
1388             return;
1389         }
1390         getSpi().engineUpdateAAD(input, inputOffset, inputLen);
1391     }
1392 
1393     /**
1394      * Continues a multi-part transformation (encryption or decryption) with
1395      * Authenticated Additional Data (AAD). AAD may only be added after the
1396      * {@code Cipher} is initialized and before any data is passed to the
1397      * instance.
1398      * <p>
1399      * This is only usable with cipher modes that support Authenticated
1400      * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM).
1401      *
1402      * @param input buffer of AAD to be used
1403      * @throws IllegalStateException
1404      *             if this cipher instance is not initialized for encryption or
1405      *             decryption.
1406      * @throws UnsupportedOperationException if the cipher does not support AEAD
1407      * @since 1.7
1408      */
updateAAD(ByteBuffer input)1409     public final void updateAAD(ByteBuffer input) {
1410         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1411             throw new IllegalStateException("Cipher is not initialized");
1412         }
1413         if (input == null) {
1414             throw new IllegalArgumentException("input == null");
1415         }
1416         getSpi().engineUpdateAAD(input);
1417     }
1418 
1419     /**
1420      * Finishes a multi-part transformation (encryption or decryption).
1421      * <p>
1422      * Processes any bytes that may have been buffered in previous {@code
1423      * update} calls.
1424      *
1425      * @return the final bytes from the transformation.
1426      * @throws IllegalBlockSizeException
1427      *             if the size of the resulting bytes is not a multiple of the
1428      *             cipher block size.
1429      * @throws BadPaddingException
1430      *             if the padding of the data does not match the padding scheme.
1431      * @throws IllegalStateException
1432      *             if this cipher instance is not initialized for encryption or
1433      *             decryption.
1434      */
doFinal()1435     public final byte[] doFinal() throws IllegalBlockSizeException,
1436             BadPaddingException {
1437         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1438             throw new IllegalStateException();
1439         }
1440         return getSpi().engineDoFinal(null, 0, 0);
1441     }
1442 
1443     /**
1444      * Finishes a multi-part transformation (encryption or decryption).
1445      * <p>
1446      * Processes any bytes that may have been buffered in previous {@code
1447      * update} calls.
1448      * <p>
1449      * The final transformed bytes are stored in the {@code output} buffer.
1450      *
1451      * @param output
1452      *            the output buffer.
1453      * @param outputOffset
1454      *            the offset in the output buffer.
1455      * @return the number of bytes placed in the output buffer.
1456      * @throws IllegalBlockSizeException
1457      *             if the size of the resulting bytes is not a multiple of the
1458      *             cipher block size.
1459      * @throws ShortBufferException
1460      *             if the size of the {@code output} buffer is too small.
1461      * @throws BadPaddingException
1462      *             if the padding of the data does not match the padding scheme.
1463      * @throws IllegalStateException
1464      *             if this cipher instance is not initialized for encryption or
1465      *             decryption.
1466      */
doFinal(byte[] output, int outputOffset)1467     public final int doFinal(byte[] output, int outputOffset)
1468             throws IllegalBlockSizeException, ShortBufferException,
1469             BadPaddingException {
1470         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1471             throw new IllegalStateException();
1472         }
1473         if (outputOffset < 0) {
1474             throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
1475         }
1476         return getSpi().engineDoFinal(null, 0, 0, output, outputOffset);
1477     }
1478 
1479     /**
1480      * Finishes a multi-part transformation (encryption or decryption).
1481      * <p>
1482      * Processes the bytes in {@code input} buffer, and any bytes that have been
1483      * buffered in previous {@code update} calls.
1484      *
1485      * @param input
1486      *            the input buffer.
1487      * @return the final bytes from the transformation.
1488      * @throws IllegalBlockSizeException
1489      *             if the size of the resulting bytes is not a multiple of the
1490      *             cipher block size.
1491      * @throws BadPaddingException
1492      *             if the padding of the data does not match the padding scheme.
1493      * @throws IllegalStateException
1494      *             if this cipher instance is not initialized for encryption or
1495      *             decryption.
1496      */
doFinal(byte[] input)1497     public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException,
1498             BadPaddingException {
1499         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1500             throw new IllegalStateException();
1501         }
1502         return getSpi().engineDoFinal(input, 0, input.length);
1503     }
1504 
1505     /**
1506      * Finishes a multi-part transformation (encryption or decryption).
1507      * <p>
1508      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1509      * inputOffset}, and any bytes that have been buffered in previous {@code
1510      * update} calls.
1511      *
1512      * @param input
1513      *            the input buffer.
1514      * @param inputOffset
1515      *            the offset in the input buffer.
1516      * @param inputLen
1517      *            the length of the input
1518      * @return the final bytes from the transformation.
1519      * @throws IllegalBlockSizeException
1520      *             if the size of the resulting bytes is not a multiple of the
1521      *             cipher block size.
1522      * @throws BadPaddingException
1523      *             if the padding of the data does not match the padding scheme.
1524      * @throws IllegalStateException
1525      *             if this cipher instance is not initialized for encryption or
1526      *             decryption.
1527      * @throws IllegalArgumentException
1528      *             if {@code inputOffset} and {@code inputLen} do not specify an
1529      *             valid chunk in the input buffer.
1530      */
doFinal(byte[] input, int inputOffset, int inputLen)1531     public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
1532             throws IllegalBlockSizeException, BadPaddingException {
1533         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1534             throw new IllegalStateException();
1535         }
1536         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1537         return getSpi().engineDoFinal(input, inputOffset, inputLen);
1538     }
1539 
1540     /**
1541      * Finishes a multi-part transformation (encryption or decryption).
1542      * <p>
1543      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1544      * inputOffset}, and any bytes that have been buffered in previous {@code
1545      * update} calls.
1546      *
1547      * @param input
1548      *            the input buffer.
1549      * @param inputOffset
1550      *            the offset in the input buffer.
1551      * @param inputLen
1552      *            the length of the input.
1553      * @param output
1554      *            the output buffer for the transformed bytes.
1555      * @return the number of bytes placed in the output buffer.
1556      * @throws ShortBufferException
1557      *             if the size of the {@code output} buffer is too small.
1558      * @throws IllegalBlockSizeException
1559      *             if the size of the resulting bytes is not a multiple of the
1560      *             cipher block size.
1561      * @throws BadPaddingException
1562      *             if the padding of the data does not match the padding scheme.
1563      * @throws IllegalStateException
1564      *             if this cipher instance is not initialized for encryption or
1565      *             decryption.
1566      * @throws IllegalArgumentException
1567      *             if {@code inputOffset} and {@code inputLen} do not specify an
1568      *             valid chunk in the input buffer.
1569      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)1570     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1571             byte[] output) throws ShortBufferException,
1572             IllegalBlockSizeException, BadPaddingException {
1573         return doFinal(input, inputOffset, inputLen, output, 0);
1574     }
1575 
1576     /**
1577      * Finishes a multi-part transformation (encryption or decryption).
1578      * <p>
1579      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1580      * inputOffset}, and any bytes that have been buffered in previous {@code
1581      * update} calls.
1582      *
1583      * @param input
1584      *            the input buffer.
1585      * @param inputOffset
1586      *            the offset in the input buffer.
1587      * @param inputLen
1588      *            the length of the input.
1589      * @param output
1590      *            the output buffer for the transformed bytes.
1591      * @param outputOffset
1592      *            the offset in the output buffer.
1593      * @return the number of bytes placed in the output buffer.
1594      * @throws ShortBufferException
1595      *             if the size of the {@code output} buffer is too small.
1596      * @throws IllegalBlockSizeException
1597      *             if the size of the resulting bytes is not a multiple of the
1598      *             cipher block size.
1599      * @throws BadPaddingException
1600      *             if the padding of the data does not match the padding scheme.
1601      * @throws IllegalStateException
1602      *             if this cipher instance is not initialized for encryption or
1603      *             decryption.
1604      * @throws IllegalArgumentException
1605      *             if {@code inputOffset} and {@code inputLen} do not specify an
1606      *             valid chunk in the input buffer.
1607      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1608     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1609             byte[] output, int outputOffset) throws ShortBufferException,
1610             IllegalBlockSizeException, BadPaddingException {
1611         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1612             throw new IllegalStateException();
1613         }
1614         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1615         return getSpi().engineDoFinal(input, inputOffset, inputLen, output,
1616                 outputOffset);
1617     }
1618 
1619     /**
1620      * Finishes a multi-part transformation (encryption or decryption).
1621      * <p>
1622      * Processes the {@code input.remaining()} bytes in {@code input} buffer at
1623      * {@code input.position()}, and any bytes that have been buffered in
1624      * previous {@code update} calls. The transformed bytes are placed into
1625      * {@code output} buffer.
1626      *
1627      * @param input
1628      *            the input buffer.
1629      * @param output
1630      *            the output buffer.
1631      * @return the number of bytes placed into the output buffer.
1632      * @throws ShortBufferException
1633      *             if the size of the {@code output} buffer is too small.
1634      * @throws IllegalBlockSizeException
1635      *             if the size of the resulting bytes is not a multiple of the
1636      *             cipher block size.
1637      * @throws BadPaddingException
1638      *             if the padding of the data does not match the padding scheme.
1639      * @throws IllegalArgumentException
1640      *             if the input buffer and the output buffer are the same
1641      *             object.
1642      * @throws IllegalStateException
1643      *             if this cipher instance is not initialized for encryption or
1644      *             decryption.
1645      */
doFinal(ByteBuffer input, ByteBuffer output)1646     public final int doFinal(ByteBuffer input, ByteBuffer output)
1647             throws ShortBufferException, IllegalBlockSizeException,
1648             BadPaddingException {
1649         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1650             throw new IllegalStateException();
1651         }
1652         if (input == output) {
1653             throw new IllegalArgumentException("input == output");
1654         }
1655         return getSpi().engineDoFinal(input, output);
1656     }
1657 
1658     /**
1659      * Wraps a key using this cipher instance.
1660      *
1661      * @param key
1662      *            the key to wrap.
1663      * @return the wrapped key.
1664      * @throws IllegalBlockSizeException
1665      *             if the size of the resulting bytes is not a multiple of the
1666      *             cipher block size.
1667      * @throws InvalidKeyException
1668      *             if this cipher instance can not wrap this key.
1669      * @throws IllegalStateException
1670      *             if this cipher instance is not initialized for wrapping.
1671      */
wrap(Key key)1672     public final byte[] wrap(Key key) throws IllegalBlockSizeException,
1673             InvalidKeyException {
1674         if (mode != WRAP_MODE) {
1675             throw new IllegalStateException();
1676         }
1677         return getSpi().engineWrap(key);
1678     }
1679 
1680     /**
1681      * Unwraps a key using this cipher instance.
1682      *
1683      * @param wrappedKey
1684      *            the wrapped key to unwrap.
1685      * @param wrappedKeyAlgorithm
1686      *            the algorithm for the wrapped key.
1687      * @param wrappedKeyType
1688      *            the type of the wrapped key (one of: {@code SECRET_KEY
1689      *            <code>, <code>PRIVATE_KEY} or {@code PUBLIC_KEY})
1690      * @return the unwrapped key
1691      * @throws InvalidKeyException
1692      *             if the {@code wrappedKey} can not be unwrapped to a key of
1693      *             type {@code wrappedKeyType} for the {@code
1694      *             wrappedKeyAlgorithm}.
1695      * @throws NoSuchAlgorithmException
1696      *             if no provider can be found that can create a key of type
1697      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
1698      * @throws IllegalStateException
1699      *             if this cipher instance is not initialized for unwrapping.
1700      */
unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)1701     public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
1702             int wrappedKeyType) throws InvalidKeyException,
1703             NoSuchAlgorithmException {
1704         if (mode != UNWRAP_MODE) {
1705             throw new IllegalStateException();
1706         }
1707         return getSpi().engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
1708                 wrappedKeyType);
1709     }
1710 
1711     /**
1712      * Returns the maximum key length for the specified transformation.
1713      *
1714      * @param transformation
1715      *            the transformation name.
1716      * @return the maximum key length, currently {@code Integer.MAX_VALUE}.
1717      * @throws NoSuchAlgorithmException
1718      *             if no provider for the specified {@code transformation} can
1719      *             be found.
1720      * @throws NullPointerException
1721      *             if {@code transformation} is {@code null}.
1722      */
getMaxAllowedKeyLength(String transformation)1723     public static final int getMaxAllowedKeyLength(String transformation)
1724             throws NoSuchAlgorithmException {
1725         if (transformation == null) {
1726             throw new NullPointerException("transformation == null");
1727         }
1728         checkTransformation(transformation);
1729         //FIXME jurisdiction policy files
1730         return Integer.MAX_VALUE;
1731     }
1732 
1733     /**
1734      * Returns the maximum cipher parameter value for the specified
1735      * transformation. If there is no maximum limit, {@code null} is returned.
1736      *
1737      * @param transformation
1738      *            the transformation name.
1739      * @return a parameter spec holding the maximum value or {@code null}.
1740      *         Currently {@code null}.
1741      * @throws NoSuchAlgorithmException
1742      *             if no provider for the specified {@code transformation} can
1743      *             be found.
1744      * @throws NullPointerException
1745      *             if {@code transformation} is {@code null}.
1746      */
getMaxAllowedParameterSpec( String transformation)1747     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
1748             String transformation) throws NoSuchAlgorithmException {
1749         if (transformation == null) {
1750             throw new NullPointerException("transformation == null");
1751         }
1752         checkTransformation(transformation);
1753         //FIXME jurisdiction policy files
1754         return null;
1755     }
1756 }
1757