• 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.SecureRandom;
30 import java.security.Security;
31 import java.security.cert.Certificate;
32 import java.security.cert.X509Certificate;
33 import java.security.spec.AlgorithmParameterSpec;
34 import java.util.Set;
35 import java.util.StringTokenizer;
36 
37 import org.apache.harmony.crypto.internal.NullCipherSpi;
38 import org.apache.harmony.crypto.internal.nls.Messages;
39 import org.apache.harmony.security.fortress.Engine;
40 
41 /**
42  * This class provides access to implementations of cryptographic ciphers for
43  * encryption and decryption. Cipher classes can not be instantiated directly,
44  * one has to call the Cipher's {@code getInstance} method with the name of a
45  * requested transformation, optionally with a provider. A transformation
46  * specifies an operation (or a set of operations) as a string in the form:
47  * <ul>
48  * <li><i>"algorithm/mode/padding"</i></li> or
49  * <li><i>"algorithm"</i></li>
50  * </ul>
51  * <i>algorithm</i> is the name of a cryptographic algorithm, <i>mode</i> is the
52  * name of a feedback mode and <i>padding</i> is the name of a padding scheme.
53  * If <i>mode</i> and/or <i>padding</i> values are omitted, provider specific
54  * default values will be used.
55  * <p>
56  * A valid transformation would be:
57  * <ul>
58  * {@code Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");}
59  * </ul>
60  * When a block cipher is requested in in stream cipher mode, the number of bits
61  * to be processed at a time can be optionally specified by appending it to the
62  * mode name. e.g. <i>"AES/CFB8/NoPadding"</i>. If no number is specified, a
63  * provider specific default value is used.
64  * </p>
65  *
66  * @since Android 1.0
67  */
68 public class Cipher {
69 
70     /**
71      * Constant for decryption operation mode.
72      *
73      * @since Android 1.0
74      */
75     public static final int DECRYPT_MODE = 2;
76 
77     /**
78      * Constant for encryption operation mode.
79      *
80      * @since Android 1.0
81      */
82     public static final int ENCRYPT_MODE = 1;
83 
84     /**
85      * Constant indicating that the key to be unwrapped is a private key.
86      *
87      * @since Android 1.0
88      */
89     public static final int PRIVATE_KEY = 2;
90 
91     /**
92      * Constant indicating that the key to be unwrapped is a public key.
93      *
94      * @since Android 1.0
95      */
96     public static final int PUBLIC_KEY = 1;
97 
98     /**
99      * Constant indicating that the key to be unwrapped is a secret key.
100      *
101      * @since Android 1.0
102      */
103     public static final int SECRET_KEY = 3;
104 
105     /**
106      * Constant for key unwrapping operation mode.
107      *
108      * @since Android 1.0
109      */
110     public static final int UNWRAP_MODE = 4;
111 
112     /**
113      * Constant for key wrapping operation mode.
114      *
115      * @since Android 1.0
116      */
117     public static final int WRAP_MODE = 3;
118 
119     private int mode;
120 
121     /**
122      * The service name.
123      */
124     private static final String SERVICE = "Cipher"; //$NON-NLS-1$
125 
126     /**
127      * Used to access common engine functionality.
128      */
129     private static final Engine engine = new Engine(SERVICE);
130 
131     /**
132      * The provider.
133      */
134     private Provider provider;
135 
136     /**
137      * The SPI implementation.
138      */
139     private CipherSpi spiImpl;
140 
141     /**
142      * The transformation.
143      */
144     private String transformation;
145 
146     private static SecureRandom sec_rand;
147 
148     /**
149      * Creates a new Cipher instance.
150      *
151      * @param cipherSpi
152      *            the implementation delegate of the cipher.
153      * @param provider
154      *            the provider of the implementation of this cipher.
155      * @param transformation
156      *            the name of the transformation that this cipher performs.
157      * @throws NullPointerException
158      *             if either cipherSpi is {@code null} or provider is {@code
159      *             null} and {@code cipherSpi} is a {@code NullCipherSpi}.
160      * @since Android 1.0
161      */
Cipher(CipherSpi cipherSpi, Provider provider, String transformation)162     protected Cipher(CipherSpi cipherSpi, Provider provider,
163             String transformation) {
164         if (cipherSpi == null) {
165             throw new NullPointerException();
166         }
167         if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
168             throw new NullPointerException();
169         }
170         this.provider = provider;
171         this.transformation = transformation;
172         this.spiImpl = cipherSpi;
173     }
174 
175     /**
176      * Creates a new Cipher for the specified transformation. The installed
177      * providers are searched in order for an implementation of the specified
178      * transformation. The first found provider providing the transformation is
179      * used to create the cipher. If no provider is found an exception is
180      * thrown.
181      *
182      * @param transformation
183      *            the name of the transformation to create a cipher for.
184      * @return a cipher for the requested transformation.
185      * @throws NoSuchAlgorithmException
186      *             if no installed provider can provide the
187      *             <i>transformation</i>, or it is {@code null}, empty or in an
188      *             invalid format.
189      * @throws NoSuchPaddingException
190      *             if no installed provider can provide the padding scheme in
191      *             the <i>transformation</i>.
192      * @since Android 1.0
193      */
getInstance(String transformation)194     public static final Cipher getInstance(String transformation)
195             throws NoSuchAlgorithmException, NoSuchPaddingException {
196         return getCipher(transformation, null);
197     }
198 
199     /**
200      * Creates a new cipher for the specified transformation provided by the
201      * specified provider.
202      *
203      * @param transformation
204      *            the name of the transformation to create a cipher for.
205      * @param provider
206      *            the name of the provider to ask for the transformation.
207      * @return a cipher for the requested transformation.
208      * @throws NoSuchAlgorithmException
209      *             if the specified provider can not provide the
210      *             <i>transformation</i>, or it is {@code null}, empty or in an
211      *             invalid format.
212      * @throws NoSuchProviderException
213      *             if no provider with the specified name can be found.
214      * @throws NoSuchPaddingException
215      *             if the requested padding scheme in the <i>transformation</i>
216      *             is not available.
217      * @throws IllegalArgumentException
218      *             if the specified provider is {@code null}.
219      * @since Android 1.0
220      */
getInstance(String transformation, String provider)221     public static final Cipher getInstance(String transformation,
222             String provider) throws NoSuchAlgorithmException,
223             NoSuchProviderException, NoSuchPaddingException {
224 
225         if (provider == null) {
226             throw new IllegalArgumentException(Messages.getString("crypto.04")); //$NON-NLS-1$
227         }
228 
229         Provider p = Security.getProvider(provider);
230         if (p == null) {
231             throw new NoSuchProviderException(Messages.getString("crypto.16", provider)); //$NON-NLS-1$
232         }
233         return getInstance(transformation, p);
234     }
235 
236     /**
237      * Creates a new cipher for the specified transformation.
238      *
239      * @param transformation
240      *            the name of the transformation to create a cipher for.
241      * @param provider
242      *            the provider to ask for the transformation.
243      * @return a cipher for the requested transformation.
244      * @throws NoSuchAlgorithmException
245      *             if the specified provider can not provide the
246      *             <i>transformation</i>, or it is {@code null}, empty or in an
247      *             invalid format.
248      * @throws NoSuchPaddingException
249      *             if the requested padding scheme in the <i>transformation</i>
250      *             is not available.
251      * @throws IllegalArgumentException
252      *             if the provider is {@code null}.
253      * @since Android 1.0
254      */
getInstance(String transformation, Provider provider)255     public static final Cipher getInstance(String transformation,
256             Provider provider) throws NoSuchAlgorithmException,
257             NoSuchPaddingException {
258         if (provider == null) {
259             throw new IllegalArgumentException(Messages.getString("crypto.04")); //$NON-NLS-1$
260         }
261         Cipher c = getCipher(transformation, provider);
262         return c;
263     }
264 
265     /**
266      * Find appropriate Cipher according the specification rules
267      *
268      * @param transformation
269      * @param provider
270      * @return
271      * @throws NoSuchAlgorithmException
272      * @throws NoSuchPaddingException
273      */
getCipher(String transformation, Provider provider)274     private static synchronized Cipher getCipher(String transformation, Provider provider)
275             throws NoSuchAlgorithmException, NoSuchPaddingException {
276 
277         if (transformation == null || "".equals(transformation)) { //$NON-NLS-1$
278             throw new NoSuchAlgorithmException(Messages.getString("crypto.17", //$NON-NLS-1$
279                     transformation));
280         }
281 
282         String[] transf = checkTransformation(transformation);
283 
284         boolean needSetPadding = false;
285         boolean needSetMode = false;
286         if (transf[1] == null && transf[2] == null) { // "algorithm"
287             if (provider == null) {
288                 engine.getInstance(transf[0], null);
289             } else {
290                 engine.getInstance(transf[0], provider, null);
291             }
292         } else {
293             String[] searhOrder = {
294                     transf[0] + "/" + transf[1] + "/" + transf[2], // "algorithm/mode/padding" //$NON-NLS-1$ //$NON-NLS-2$
295                     transf[0] + "/" + transf[1], // "algorithm/mode" //$NON-NLS-1$
296                     transf[0] + "//" + transf[2], // "algorithm//padding" //$NON-NLS-1$
297                     transf[0] // "algorithm"
298             };
299             int i;
300             for (i = 0; i < searhOrder.length; i++) {
301                 try {
302                     if (provider == null) {
303                         engine.getInstance(searhOrder[i], null);
304                     } else {
305                         engine.getInstance(searhOrder[i], provider, null);
306                     }
307                     break;
308                 } catch (NoSuchAlgorithmException e) {
309                     if ( i == searhOrder.length-1) {
310                         throw new NoSuchAlgorithmException(transformation);
311                     }
312                 }
313             }
314             switch (i) {
315             case 1: // "algorithm/mode"
316                 needSetPadding = true;
317                 break;
318             case 2: // "algorithm//padding"
319                 needSetMode = true;
320                 break;
321             case 3: // "algorithm"
322                 needSetPadding = true;
323                 needSetMode = true;
324             }
325         }
326         CipherSpi cspi;
327         try {
328             cspi = (CipherSpi) engine.spi;
329         } catch (ClassCastException e) {
330             throw new NoSuchAlgorithmException(e);
331         }
332         Cipher c = new Cipher(cspi, engine.provider, transformation);
333         if (needSetMode) {
334             c.spiImpl.engineSetMode(transf[1]);
335         }
336         if (needSetPadding) {
337             c.spiImpl.engineSetPadding(transf[2]);
338         }
339         return c;
340     }
341 
checkTransformation(String transformation)342     private static String[] checkTransformation(String transformation)
343             throws NoSuchAlgorithmException {
344         String[] transf = { null, null, null };
345         StringTokenizer st;
346         int i = 0;
347         for (st = new StringTokenizer(transformation, "/"); st //$NON-NLS-1$
348                 .hasMoreElements();) {
349             if (i > 2) {
350                 throw new NoSuchAlgorithmException(Messages.getString("crypto.17", //$NON-NLS-1$
351                         transformation));
352             }
353             transf[i] = st.nextToken();
354             if (transf[i] != null) {
355                 transf[i] = transf[i].trim();
356                 if ("".equals(transf[i])) { //$NON-NLS-1$
357                     transf[i] = null;
358                 }
359                 i++;
360             }
361         }
362         if (transf[0] == null) {
363             throw new NoSuchAlgorithmException(Messages.getString("crypto.17", //$NON-NLS-1$
364                     transformation));
365         }
366         if (!(transf[1] == null && transf[2] == null)
367                 && (transf[1] == null || transf[2] == null)) {
368             throw new NoSuchAlgorithmException(Messages.getString("crypto.17", //$NON-NLS-1$
369                     transformation));
370         }
371         return transf;
372     }
373 
374     /**
375      * Returns the provider of this cipher instance.
376      *
377      * @return the provider of this cipher instance.
378      * @since Android 1.0
379      */
getProvider()380     public final Provider getProvider() {
381         return provider;
382     }
383 
384     /**
385      * Returns the name of the algorithm of this cipher instance.
386      * <p>
387      * This is the name of the <i>transformation</i> argument used in the
388      * {@code getInstance} call creating this object.
389      * </p>
390      *
391      * @return the name of the algorithm of this cipher instance.
392      * @since Android 1.0.
393      */
getAlgorithm()394     public final String getAlgorithm() {
395         return transformation;
396     }
397 
398     /**
399      * Returns this ciphers block size (in bytes).
400      *
401      * @return this ciphers block size.
402      * @since Android 1.0
403      */
getBlockSize()404     public final int getBlockSize() {
405         return spiImpl.engineGetBlockSize();
406     }
407 
408     /**
409      * Returns the length in bytes an output buffer needs to be when this cipher
410      * is updated with {@code inputLen} bytes.
411      *
412      * @param inputLen
413      *            the number of bytes of the input.
414      * @return the output buffer length for the input length.
415      * @throws IllegalStateException
416      *             if this cipher instance is in an invalid state.
417      * @since Android 1.0
418      */
getOutputSize(int inputLen)419     public final int getOutputSize(int inputLen) {
420         if (mode == 0) {
421             throw new IllegalStateException(
422                     Messages.getString("crypto.18")); //$NON-NLS-1$
423         }
424         return spiImpl.engineGetOutputSize(inputLen);
425     }
426 
427     /**
428      * Returns the <i>initialization vector</i> for this cipher instance.
429      *
430      * @return the <i>initialization vector</i> for this cipher instance.
431      * @since Android 1.0
432      */
getIV()433     public final byte[] getIV() {
434         return spiImpl.engineGetIV();
435     }
436 
437     /**
438      * Returns the parameters that where used to create this cipher instance.
439      * <p>
440      * These may be a the same parameters that were used to create this cipher
441      * instance, or may be a combination of default and random parameters,
442      * depending on the underlying cipher implementation.
443      *
444      * @return the parameters that where used to create this cipher instance, or
445      *         {@code null} if this cipher instance does not have any
446      *         parameters.
447      * @since Android 1.0
448      */
getParameters()449     public final AlgorithmParameters getParameters() {
450         return spiImpl.engineGetParameters();
451     }
452 
453     /**
454      * Returns the exemption mechanism associated with this cipher.
455      *
456      * @return currently {@code null}
457      * @since Android 1.0
458      */
getExemptionMechanism()459     public final ExemptionMechanism getExemptionMechanism() {
460         //FIXME implement getExemptionMechanism
461 
462         //        try {
463         //            return ExemptionMechanism.getInstance(transformation, provider);
464         //        } catch (NoSuchAlgorithmException e) {
465         return null;
466         //        }
467 
468     }
469 
470     /**
471      * Initializes this cipher instance with the specified key.
472      * <p>
473      * The cipher is initialized for the specified operational mode (one of:
474      * encryption, decryption, key wrapping or key unwrapping) depending on
475      * {@code opmode}.
476      * </p>
477      * If this cipher instance needs any algorithm parameters or random values
478      * that the specified key can not provide, the underlying implementation of
479      * this cipher is supposed to generate the required parameters (using its
480      * provider or random values).
481      * <p>
482      * When a cipher instance is initialized by a call to any of the {@code
483      * init} methods, the state of the instance is overridden, meaning that it
484      * is equivalent to creating a new instance and calling its {@code init}
485      * method.
486      * </p>
487      *
488      * @param opmode
489      *            the operation this cipher instance should be initialized for
490      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
491      *            WRAP_MODE} or {@code UNWRAP_MODE}).
492      * @param key
493      *            the input key for the operation.
494      * @throws InvalidKeyException
495      *             if the specified key can not be used to initialize this
496      *             cipher instance.
497      * @since Android 1.0
498      */
init(int opmode, Key key)499     public final void init(int opmode, Key key) throws InvalidKeyException {
500         if (sec_rand == null) {
501             // In theory it might be thread-unsafe but in the given case it's OK
502             // since it does not matter which SecureRandom instance is passed
503             // to the init()
504             sec_rand = new SecureRandom();
505         }
506         init(opmode, key, sec_rand);
507     }
508 
509     /**
510      * Initializes this cipher instance with the specified key and a source of
511      * randomness.
512      * <p>
513      * The cipher is initialized for the specified operational mode (one of:
514      * encryption, decryption, key wrapping or key unwrapping) depending on
515      * {@code opmode}.
516      * </p>
517      * If this cipher instance needs any algorithm parameters or random values
518      * that the specified key can not provide, the underlying implementation of
519      * this cipher is supposed to generate the required parameters (using its
520      * provider or random values). Random values are generated using {@code
521      * random};
522      * <p>
523      * When a cipher instance is initialized by a call to any of the {@code
524      * init} methods, the state of the instance is overridden, means it is
525      * equivalent to creating a new instance and calling it {@code init} method.
526      * </p>
527      *
528      * @param opmode
529      *            the operation this cipher instance should be initialized for
530      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
531      *            WRAP_MODE} or {@code UNWRAP_MODE}).
532      * @param key
533      *            the input key for the operation.
534      * @param random
535      *            the source of randomness to use.
536      * @throws InvalidKeyException
537      *             if the specified key can not be used to initialize this
538      *             cipher instance.
539      * @throws InvalidParameterException
540      *             if the specified opmode is invalid.
541      * @since Android 1.0
542      */
init(int opmode, Key key, SecureRandom random)543     public final void init(int opmode, Key key, SecureRandom random)
544             throws InvalidKeyException {
545         if (opmode != ENCRYPT_MODE && opmode != DECRYPT_MODE
546                 && opmode != UNWRAP_MODE && opmode != WRAP_MODE) {
547             throw new InvalidParameterException(Messages.getString("crypto.19")); //$NON-NLS-1$
548         }
549         //        FIXME InvalidKeyException
550         //        if keysize exceeds the maximum allowable keysize
551         //        (jurisdiction policy files)
552         spiImpl.engineInit(opmode, key, random);
553         mode = opmode;
554     }
555 
556     /**
557      * Initializes this cipher instance with the specified key and algorithm
558      * parameters.
559      * <p>
560      * The cipher is initialized for the specified operational mode (one of:
561      * encryption, decryption, key wrapping or key unwrapping).
562      * </p>
563      * If this cipher instance needs any algorithm parameters and {@code params}
564      * is {@code null}, the underlying implementation of this cipher is supposed
565      * to generate the required parameters (using its provider or random
566      * values).
567      * <p>
568      * When a cipher instance is initialized by a call to any of the {@code
569      * init} methods, the state of the instance is overridden, means it is
570      * equivalent to creating a new instance and calling it {@code init} method.
571      * </p>
572      *
573      * @param opmode
574      *            the operation this cipher instance should be initialized for
575      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
576      *            WRAP_MODE} or {@code UNWRAP_MODE}).
577      * @param key
578      *            the input key for the operation.
579      * @param params
580      *            the algorithm parameters.
581      * @throws InvalidKeyException
582      *             if the specified key can not be used to initialize this
583      *             cipher instance.
584      * @throws InvalidAlgorithmParameterException
585      *             it the specified parameters are inappropriate for this
586      *             cipher.
587      * @since Android 1.0
588      */
init(int opmode, Key key, AlgorithmParameterSpec params)589     public final void init(int opmode, Key key, AlgorithmParameterSpec params)
590             throws InvalidKeyException, InvalidAlgorithmParameterException {
591         if (sec_rand == null) {
592             sec_rand = new SecureRandom();
593         }
594         init(opmode, key, params, sec_rand);
595     }
596 
597     /**
598      * Initializes this cipher instance with the specified key, algorithm
599      * parameters and a source of randomness.
600      * <p>
601      * The cipher is initialized for the specified operational mode (one of:
602      * encryption, decryption, key wrapping or key unwrapping) depending on
603      * {@code opmode}.
604      * <p>
605      * If this cipher instance needs any algorithm parameters and {@code params}
606      * is {@code null}, the underlying implementation of this cipher is supposed
607      * to generate the required parameters (using its provider or random
608      * values). Random values are generated using {@code random};
609      * <p>
610      * When a cipher instance is initialized by a call to any of the {@code
611      * init} methods, the state of the instance is overridden, meaning that it
612      * is equivalent to creating a new instance and calling it {@code init}
613      * method.
614      *
615      * @param opmode
616      *            the operation this cipher instance should be initialized for
617      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
618      *            WRAP_MODE} or {@code UNWRAP_MODE}).
619      * @param key
620      *            the input key for the operation.
621      * @param params
622      *            the algorithm parameters.
623      * @param random
624      *            the source of randomness to use.
625      * @throws InvalidKeyException
626      *             if the specified key can not be used to initialize this
627      *             cipher instance.
628      * @throws InvalidAlgorithmParameterException
629      *             it the specified parameters are inappropriate for this
630      *             cipher.
631      * @throws InvalidParameterException
632      *             if the specified {@code opmode} is invalid.
633      * @since Android 1.0
634      */
init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)635     public final void init(int opmode, Key key, AlgorithmParameterSpec params,
636             SecureRandom random) throws InvalidKeyException,
637             InvalidAlgorithmParameterException {
638         if (opmode != ENCRYPT_MODE && opmode != DECRYPT_MODE
639                 && opmode != UNWRAP_MODE && opmode != WRAP_MODE) {
640             throw new InvalidParameterException(Messages.getString("crypto.19")); //$NON-NLS-1$
641         }
642         //        FIXME InvalidKeyException
643         //        if keysize exceeds the maximum allowable keysize
644         //        (jurisdiction policy files)
645         //        FIXME InvalidAlgorithmParameterException
646         //        cryptographic strength exceed the legal limits
647         //        (jurisdiction policy files)
648         spiImpl.engineInit(opmode, key, params, random);
649         mode = opmode;
650     }
651 
652     /**
653      * Initializes this cipher instance with the specified key and algorithm
654      * parameters.
655      * <p>
656      * The cipher is initialized for the specified operation (one of:
657      * encryption, decryption, key wrapping or key unwrapping) depending on
658      * {@code opmode}.
659      * </p>
660      * If this cipher instance needs any algorithm parameters and {@code params}
661      * is {@code null}, the underlying implementation of this cipher is supposed
662      * to generate the required parameters (using its provider or random
663      * values).
664      * <p>
665      * When a cipher instance is initialized by a call to any of the {@code
666      * init} methods, the state of the instance is overridden, meaning that it
667      * is equivalent to creating a new instance and calling it {@code init}
668      * method.
669      * </p>
670      *
671      * @param opmode
672      *            the operation this cipher instance should be initialized for
673      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
674      *            WRAP_MODE} or {@code UNWRAP_MODE}).
675      * @param key
676      *            the input key for the operation.
677      * @param params
678      *            the algorithm parameters.
679      * @throws InvalidKeyException
680      *             if the specified key can not be used to initialize this
681      *             cipher instance.
682      * @throws InvalidAlgorithmParameterException
683      *             it the specified parameters are inappropriate for this
684      *             cipher.
685      * @since Android 1.0
686      */
init(int opmode, Key key, AlgorithmParameters params)687     public final void init(int opmode, Key key, AlgorithmParameters params)
688             throws InvalidKeyException, InvalidAlgorithmParameterException {
689         if (sec_rand == null) {
690             sec_rand = new SecureRandom();
691         }
692         init(opmode, key, params, sec_rand);
693     }
694 
695     /**
696      * Initializes this cipher instance with the specified key, algorithm
697      * parameters and a source of randomness.
698      * <p>
699      * The cipher will be initialized for the specified operation (one of:
700      * encryption, decryption, key wrapping or key unwrapping) depending on
701      * {@code opmode}.
702      * </p>
703      * If this cipher instance needs any algorithm parameters and {@code params}
704      * is {@code null}, the underlying implementation of this cipher is supposed
705      * to generate the required parameters (using its provider or random
706      * values). Random values are generated using {@code random}.
707      * <p>
708      * When a cipher instance is initialized by a call to any of the {@code
709      * init} methods, the state of the instance is overridden, means it is
710      * equivalent to creating a new instance and calling it {@code init} method.
711      * </p>
712      *
713      * @param opmode
714      *            the operation this cipher instance should be initialized for
715      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
716      *            WRAP_MODE} or {@code UNWRAP_MODE}).
717      * @param key
718      *            the input key for the operation.
719      * @param params
720      *            the algorithm parameters.
721      * @param random
722      *            the source of randomness to use.
723      * @throws InvalidKeyException
724      *             if the specified key can not be used to initialize this
725      *             cipher instance.
726      * @throws InvalidAlgorithmParameterException
727      *             if the specified parameters are inappropriate for this
728      *             cipher.
729      * @throws InvalidParameterException
730      *             if the specified {@code opmode} is invalid.
731      * @since Android 1.0
732      */
init(int opmode, Key key, AlgorithmParameters params, SecureRandom random)733     public final void init(int opmode, Key key, AlgorithmParameters params,
734             SecureRandom random) throws InvalidKeyException,
735             InvalidAlgorithmParameterException {
736         if (opmode != ENCRYPT_MODE && opmode != DECRYPT_MODE
737                 && opmode != UNWRAP_MODE && opmode != WRAP_MODE) {
738             throw new InvalidParameterException(Messages.getString("crypto.19")); //$NON-NLS-1$
739         }
740         //        FIXME InvalidKeyException
741         //        if keysize exceeds the maximum allowable keysize
742         //        (jurisdiction policy files)
743         //        FIXME InvalidAlgorithmParameterException
744         //        cryptographic strength exceed the legal limits
745         //        (jurisdiction policy files)
746         spiImpl.engineInit(opmode, key, params, random);
747         mode = opmode;
748     }
749 
750     /**
751      * Initializes this cipher instance with the public key from the specified
752      * certificate.
753      * <p>
754      * The cipher will be initialized for the specified operation (one of:
755      * encryption, decryption, key wrapping or key unwrapping) depending on
756      * {@code opmode}.
757      * <p>
758      * It the type of the certificate is X.509 and the certificate has a <i>key
759      * usage</i> extension field marked as critical, the specified {@code
760      * opmode} has the be enabled for this key, otherwise an {@code
761      * InvalidKeyException} is thrown.
762      * <p>
763      * If this cipher instance needs any algorithm parameters that the key in
764      * the certificate can not provide, the underlying implementation of this
765      * cipher is supposed to generate the required parameters (using its
766      * provider or random values).
767      * <p>
768      * When a cipher instance is initialized by a call to any of the {@code
769      * init} methods, the state of the instance is overridden, means it is
770      * equivalent to creating a new instance and calling it {@code init} method.
771      *
772      * @param opmode
773      *            the operation this cipher instance should be initialized for
774      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
775      *            WRAP_MODE} or {@code UNWRAP_MODE}).
776      * @param certificate
777      *            the certificate.
778      * @throws InvalidKeyException
779      *             if the public key in the certificate can not be used to
780      *             initialize this cipher instance.
781      * @since Android 1.0
782      */
init(int opmode, Certificate certificate)783     public final void init(int opmode, Certificate certificate)
784             throws InvalidKeyException {
785         if (sec_rand == null) {
786             sec_rand = new SecureRandom();
787         }
788         init(opmode, certificate, sec_rand);
789     }
790 
791     /**
792      * Initializes this cipher instance with the public key from the specified
793      * certificate and a source of randomness.
794      * <p>
795      * The cipher will be initialized for the specified operation (one of:
796      * encryption, decryption, key wrapping or key unwrapping) depending on
797      * {@code opmode}.
798      * </p>
799      * It the type of the certificate is X.509 and the certificate has a <i>key
800      * usage</i> extension field marked as critical, the specified {@code
801      * opmode} has the be enabled for this key, otherwise an {@code
802      * InvalidKeyException} is thrown.
803      * <p>
804      * If this cipher instance needs any algorithm parameters that the key in
805      * the certificate can not provide, the underlying implementation of this
806      * cipher is supposed to generate the required parameters (using its
807      * provider or random values). Random values are generated using {@code
808      * random}.
809      * </p>
810      * When a cipher instance is initialized by a call to any of the {@code
811      * init} methods, the state of the instance is overridden, means it is
812      * equivalent to creating a new instance and calling it {@code init} method.
813      *
814      * @param opmode
815      *            the operation this cipher instance should be initialized for
816      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
817      *            WRAP_MODE} or {@code UNWRAP_MODE}).
818      * @param certificate
819      *            the certificate.
820      * @param random
821      *            the source of randomness to be used.
822      * @throws InvalidKeyException
823      *             if the public key in the certificate can not be used to
824      *             initialize this cipher instance.
825      * @since Android 1.0
826      */
init(int opmode, Certificate certificate, SecureRandom random)827     public final void init(int opmode, Certificate certificate,
828             SecureRandom random) throws InvalidKeyException {
829         if (opmode != ENCRYPT_MODE && opmode != DECRYPT_MODE
830                 && opmode != UNWRAP_MODE && opmode != WRAP_MODE) {
831             throw new InvalidParameterException(Messages.getString("crypto.19")); //$NON-NLS-1$
832         }
833         if (certificate instanceof X509Certificate) {
834             Set<String> ce = ((X509Certificate) certificate).getCriticalExtensionOIDs();
835             boolean critical = false;
836             if (ce != null && !ce.isEmpty()) {
837                 for (String oid : ce) {
838                     if (oid.equals("2.5.29.15")) { //KeyUsage OID = 2.5.29.15 //$NON-NLS-1$
839                         critical = true;
840                         break;
841                     }
842                 }
843                 if (critical) {
844                     boolean[] keyUsage = ((X509Certificate) certificate)
845                             .getKeyUsage();
846                     // As specified in RFC 3280 -
847                     // Internet X.509 Public Key Infrastructure
848                     // Certificate and Certificate Revocation List (CRL) Profile.
849                     // (http://www.ietf.org/rfc/rfc3280.txt)
850                     //
851                     // KeyUsage ::= BIT STRING {digitalSignature (0),
852                     //                          ...
853                     //                          encipherOnly (7),
854                     //                          decipherOnly (8) }
855                     if (keyUsage != null) {
856                         if (opmode == ENCRYPT_MODE && (!keyUsage[7])) {
857                             throw new InvalidKeyException(
858                                     Messages.getString("crypto.1A")); //$NON-NLS-1$
859                         } else if (opmode == DECRYPT_MODE && (!keyUsage[8])) {
860                             throw new InvalidKeyException(
861                                     Messages.getString("crypto.1B")); //$NON-NLS-1$
862                         }
863                     }
864                 }
865             }
866         }
867         //        FIXME InvalidKeyException
868         //        if keysize exceeds the maximum allowable keysize
869         //        (jurisdiction policy files)
870         spiImpl.engineInit(opmode, certificate.getPublicKey(), random);
871         mode = opmode;
872     }
873 
874     /**
875      * Continues a multi-part transformation (encryption or decryption). The
876      * transformed bytes are returned.
877      *
878      * @param input
879      *            the input bytes to transform.
880      * @return the transformed bytes in a new buffer, or {@code null} if the
881      *         input has zero length.
882      * @throws IllegalStateException
883      *             if this cipher instance is not initialized for encryption or
884      *             decryption.
885      * @throws IllegalArgumentException
886      *             if the input is {@code null}.
887      * @since Android 1.0
888      */
update(byte[] input)889     public final byte[] update(byte[] input) {
890         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
891             throw new IllegalStateException(
892                     Messages.getString("crypto.1C")); //$NON-NLS-1$
893         }
894         if (input == null) {
895             throw new IllegalArgumentException(Messages.getString("crypto.1D")); //$NON-NLS-1$
896         }
897         if (input.length == 0) {
898             return null;
899         }
900         return spiImpl.engineUpdate(input, 0, input.length);
901     }
902 
903     /**
904      * Continues a multi-part transformation (encryption or decryption). The
905      * transformed bytes are returned.
906      *
907      * @param input
908      *            the input bytes to transform.
909      * @param inputOffset
910      *            the offset in the input to start.
911      * @param inputLen
912      *            the length of the input to transform.
913      * @return the transformed bytes in a new buffer, or {@code null} if the
914      *         input has zero length.
915      * @throws IllegalStateException
916      *             if this cipher instance is not initialized for encryption or
917      *             decryption.
918      * @throws IllegalArgumentException
919      *             if the input is {@code null}, or if {@code inputOffset} and
920      *             {@code inputLen} do not specify a valid chunk in the input
921      *             buffer.
922      * @since Android 1.0
923      */
update(byte[] input, int inputOffset, int inputLen)924     public final byte[] update(byte[] input, int inputOffset, int inputLen) {
925         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
926             throw new IllegalStateException(
927                     Messages.getString("crypto.1C")); //$NON-NLS-1$
928         }
929         if (input == null) {
930             throw new IllegalArgumentException(Messages.getString("crypto.1D")); //$NON-NLS-1$
931         }
932         if (inputOffset < 0 || inputLen < 0
933                 || inputLen > input.length
934                 || inputOffset > input.length - inputLen) {
935             throw new IllegalArgumentException(
936                     Messages.getString("crypto.1E")); //$NON-NLS-1$
937         }
938         if (input.length == 0) {
939             return null;
940         }
941         return spiImpl.engineUpdate(input, inputOffset, inputLen);
942     }
943 
944     /**
945      * Continues a multi-part transformation (encryption or decryption). The
946      * transformed bytes are stored in the {@code output} buffer.
947      * <p>
948      * If the size of the {@code output} buffer is too small to hold the result,
949      * a {@code ShortBufferException} is thrown. Use
950      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
951      * output buffer.
952      * </p>
953      *
954      * @param input
955      *            the input bytes to transform.
956      * @param inputOffset
957      *            the offset in the input to start.
958      * @param inputLen
959      *            the length of the input to transform.
960      * @param output
961      *            the output buffer.
962      * @return the number of bytes placed in output.
963      * @throws ShortBufferException
964      *             if the size of the {@code output} buffer is too small.
965      * @throws IllegalStateException
966      *             if this cipher instance is not initialized for encryption or
967      *             decryption.
968      * @throws IllegalArgumentException
969      *             if the input is {@code null}, the output is {@code null}, or
970      *             if {@code inputOffset} and {@code inputLen} do not specify a
971      *             valid chunk in the input buffer.
972      * @since Android 1.0
973      */
update(byte[] input, int inputOffset, int inputLen, byte[] output)974     public final int update(byte[] input, int inputOffset, int inputLen,
975             byte[] output) throws ShortBufferException {
976         return update(input, inputOffset, inputLen, output, 0);
977     }
978 
979     /**
980      * Continues a multi-part transformation (encryption or decryption). The
981      * transformed bytes are stored in the {@code output} buffer.
982      * <p>
983      * If the size of the {@code output} buffer is too small to hold the result,
984      * a {@code ShortBufferException} is thrown. Use
985      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
986      * output buffer.
987      * </p>
988      *
989      * @param input
990      *            the input bytes to transform.
991      * @param inputOffset
992      *            the offset in the input to start.
993      * @param inputLen
994      *            the length of the input to transform.
995      * @param output
996      *            the output buffer.
997      * @param outputOffset
998      *            the offset in the output buffer.
999      * @return the number of bytes placed in output.
1000      * @throws ShortBufferException
1001      *             if the size of the {@code output} buffer is too small.
1002      * @throws IllegalStateException
1003      *             if this cipher instance is not initialized for encryption or
1004      *             decryption.
1005      * @throws IllegalArgumentException
1006      *             if the input is {@code null}, the output is {@code null}, or
1007      *             if {@code inputOffset} and {@code inputLen} do not specify a
1008      *             valid chunk in the input buffer.
1009      * @since Android 1.0
1010      */
update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1011     public final int update(byte[] input, int inputOffset, int inputLen,
1012             byte[] output, int outputOffset) throws ShortBufferException {
1013         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1014             throw new IllegalStateException(
1015                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1016         }
1017         if (input == null) {
1018             throw new IllegalArgumentException(Messages.getString("crypto.1D")); //$NON-NLS-1$
1019         }
1020         if (output == null) {
1021             throw new IllegalArgumentException(Messages.getString("crypto.1F")); //$NON-NLS-1$
1022         }
1023         if (outputOffset < 0) {
1024             throw new IllegalArgumentException(
1025                     Messages.getString("crypto.20")); //$NON-NLS-1$
1026         }
1027         if (inputOffset < 0 || inputLen < 0
1028                 || inputLen > input.length
1029                 || inputOffset > input.length - inputLen) {
1030             throw new IllegalArgumentException(
1031                     Messages.getString("crypto.21")); //$NON-NLS-1$
1032         }
1033         if (input.length == 0) {
1034             return 0;
1035         }
1036         return spiImpl.engineUpdate(input, inputOffset, inputLen, output,
1037                 outputOffset);
1038     }
1039 
1040     /**
1041      * Continues a multi-part transformation (encryption or decryption). The
1042      * {@code input.remaining()} bytes starting at {@code input.position()} are
1043      * transformed and stored in the {@code output} buffer.
1044      * <p>
1045      * If the {@code output.remaining()} is too small to hold the transformed
1046      * bytes a {@code ShortBufferException} is thrown. Use
1047      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
1048      * output buffer.
1049      * </p>
1050      *
1051      * @param input
1052      *            the input buffer to transform.
1053      * @param output
1054      *            the output buffer to store the result within.
1055      * @return the number of bytes stored in the output buffer.
1056      * @throws ShortBufferException
1057      *             if the size of the {@code output} buffer is too small.
1058      * @throws IllegalStateException
1059      *             if this cipher instance is not initialized for encryption or
1060      *             decryption.
1061      * @throws IllegalArgumentException
1062      *             if the input buffer and the output buffer are the identical
1063      *             object.
1064      * @since Android 1.0
1065      */
update(ByteBuffer input, ByteBuffer output)1066     public final int update(ByteBuffer input, ByteBuffer output)
1067             throws ShortBufferException {
1068         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1069             throw new IllegalStateException(
1070                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1071         }
1072         if (input == output) {
1073             throw new IllegalArgumentException(
1074                     Messages.getString("crypto.22")); //$NON-NLS-1$
1075         }
1076         return spiImpl.engineUpdate(input, output);
1077     }
1078 
1079     /**
1080      * Finishes a multi-part transformation (encryption or decryption).
1081      * <p>
1082      * Processes any bytes that may have been buffered in previous {@code
1083      * update} calls.
1084      * </p>
1085      *
1086      * @return the final bytes from the transformation.
1087      * @throws IllegalBlockSizeException
1088      *             if the size of the resulting bytes is not a multiple of the
1089      *             cipher block size.
1090      * @throws BadPaddingException
1091      *             if the padding of the data does not match the padding scheme.
1092      * @throws IllegalStateException
1093      *             if this cipher instance is not initialized for encryption or
1094      *             decryption.
1095      * @since Android 1.0
1096      */
doFinal()1097     public final byte[] doFinal() throws IllegalBlockSizeException,
1098             BadPaddingException {
1099         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1100             throw new IllegalStateException(
1101                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1102         }
1103         return spiImpl.engineDoFinal(null, 0, 0);
1104     }
1105 
1106     /**
1107      * Finishes a multi-part transformation (encryption or decryption).
1108      * <p>
1109      * Processes any bytes that may have been buffered in previous {@code
1110      * update} calls.
1111      * </p>
1112      * The final transformed bytes are stored in the {@code output} buffer.
1113      *
1114      * @param output
1115      *            the output buffer.
1116      * @param outputOffset
1117      *            the offset in the output buffer.
1118      * @return the number of bytes placed in the output buffer.
1119      * @throws IllegalBlockSizeException
1120      *             if the size of the resulting bytes is not a multiple of the
1121      *             cipher block size.
1122      * @throws ShortBufferException
1123      *             if the size of the {@code output} buffer is too small.
1124      * @throws BadPaddingException
1125      *             if the padding of the data does not match the padding scheme.
1126      * @throws IllegalStateException
1127      *             if this cipher instance is not initialized for encryption or
1128      *             decryption.
1129      * @since Android 1.0
1130      */
doFinal(byte[] output, int outputOffset)1131     public final int doFinal(byte[] output, int outputOffset)
1132             throws IllegalBlockSizeException, ShortBufferException,
1133             BadPaddingException {
1134         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1135             throw new IllegalStateException(
1136                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1137         }
1138         if (outputOffset < 0) {
1139             throw new IllegalArgumentException(
1140                     Messages.getString("crypto.20")); //$NON-NLS-1$
1141         }
1142         return spiImpl.engineDoFinal(null, 0, 0, output, outputOffset);
1143     }
1144 
1145     /**
1146      * Finishes a multi-part transformation (encryption or decryption).
1147      * <p>
1148      * Processes the bytes in {@code input} buffer, and any bytes that have been
1149      * buffered in previous {@code update} calls.
1150      * </p>
1151      *
1152      * @param input
1153      *            the input buffer.
1154      * @return the final bytes from the transformation.
1155      * @throws IllegalBlockSizeException
1156      *             if the size of the resulting bytes is not a multiple of the
1157      *             cipher block size.
1158      * @throws BadPaddingException
1159      *             if the padding of the data does not match the padding scheme.
1160      * @throws IllegalStateException
1161      *             if this cipher instance is not initialized for encryption or
1162      *             decryption.
1163      * @since Android 1.0
1164      */
doFinal(byte[] input)1165     public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException,
1166             BadPaddingException {
1167         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1168             throw new IllegalStateException(
1169                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1170         }
1171         return spiImpl.engineDoFinal(input, 0, input.length);
1172     }
1173 
1174     /**
1175      * Finishes a multi-part transformation (encryption or decryption).
1176      * <p>
1177      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1178      * inputOffset}, and any bytes that have been buffered in previous {@code
1179      * update} calls.
1180      *
1181      * @param input
1182      *            the input buffer.
1183      * @param inputOffset
1184      *            the offset in the input buffer.
1185      * @param inputLen
1186      *            the length of the input
1187      * @return the final bytes from the transformation.
1188      * @throws IllegalBlockSizeException
1189      *             if the size of the resulting bytes is not a multiple of the
1190      *             cipher block size.
1191      * @throws BadPaddingException
1192      *             if the padding of the data does not match the padding scheme.
1193      * @throws IllegalStateException
1194      *             if this cipher instance is not initialized for encryption or
1195      *             decryption.
1196      * @throws IllegalArgumentException
1197      *             if {@code inputOffset} and {@code inputLen} do not specify an
1198      *             valid chunk in the input buffer.
1199      * @since Android 1.0
1200      */
doFinal(byte[] input, int inputOffset, int inputLen)1201     public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
1202             throws IllegalBlockSizeException, BadPaddingException {
1203         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1204             throw new IllegalStateException(
1205                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1206         }
1207         if (inputOffset < 0 || inputLen < 0
1208                 || inputOffset + inputLen > input.length) {
1209             throw new IllegalArgumentException(
1210                     Messages.getString("crypto.1E")); //$NON-NLS-1$
1211         }
1212         return spiImpl.engineDoFinal(input, inputOffset, inputLen);
1213     }
1214 
1215     /**
1216      * Finishes a multi-part transformation (encryption or decryption).
1217      * <p>
1218      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1219      * inputOffset}, and any bytes that have been buffered in previous {@code
1220      * update} calls.
1221      *
1222      * @param input
1223      *            the input buffer.
1224      * @param inputOffset
1225      *            the offset in the input buffer.
1226      * @param inputLen
1227      *            the length of the input.
1228      * @param output
1229      *            the output buffer for the transformed bytes.
1230      * @return the number of bytes placed in the output buffer.
1231      * @throws ShortBufferException
1232      *             if the size of the {@code output} buffer is too small.
1233      * @throws IllegalBlockSizeException
1234      *             if the size of the resulting bytes is not a multiple of the
1235      *             cipher block size.
1236      * @throws BadPaddingException
1237      *             if the padding of the data does not match the padding scheme.
1238      * @throws IllegalStateException
1239      *             if this cipher instance is not initialized for encryption or
1240      *             decryption.
1241      * @throws IllegalArgumentException
1242      *             if {@code inputOffset} and {@code inputLen} do not specify an
1243      *             valid chunk in the input buffer.
1244      * @since Android 1.0
1245      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)1246     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1247             byte[] output) throws ShortBufferException,
1248             IllegalBlockSizeException, BadPaddingException {
1249         return doFinal(input, inputOffset, inputLen, output, 0);
1250     }
1251 
1252     /**
1253      * Finishes a multi-part transformation (encryption or decryption).
1254      * <p>
1255      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1256      * inputOffset}, and any bytes that have been buffered in previous {@code
1257      * update} calls.
1258      * </p>
1259      *
1260      * @param input
1261      *            the input buffer.
1262      * @param inputOffset
1263      *            the offset in the input buffer.
1264      * @param inputLen
1265      *            the length of the input.
1266      * @param output
1267      *            the output buffer for the transformed bytes.
1268      * @param outputOffset
1269      *            the offset in the output buffer.
1270      * @return the number of bytes placed in the output buffer.
1271      * @throws ShortBufferException
1272      *             if the size of the {@code output} buffer is too small.
1273      * @throws IllegalBlockSizeException
1274      *             if the size of the resulting bytes is not a multiple of the
1275      *             cipher block size.
1276      * @throws BadPaddingException
1277      *             if the padding of the data does not match the padding scheme.
1278      * @throws IllegalStateException
1279      *             if this cipher instance is not initialized for encryption or
1280      *             decryption.
1281      * @throws IllegalArgumentException
1282      *             if {@code inputOffset} and {@code inputLen} do not specify an
1283      *             valid chunk in the input buffer.
1284      * @since Android 1.0
1285      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1286     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1287             byte[] output, int outputOffset) throws ShortBufferException,
1288             IllegalBlockSizeException, BadPaddingException {
1289         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1290             throw new IllegalStateException(
1291                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1292         }
1293         if (inputOffset < 0 || inputLen < 0
1294                 || inputOffset + inputLen > input.length) {
1295             throw new IllegalArgumentException(
1296                     Messages.getString("crypto.1E")); //$NON-NLS-1$
1297         }
1298         return spiImpl.engineDoFinal(input, inputOffset, inputLen, output,
1299                 outputOffset);
1300     }
1301 
1302     /**
1303      * Finishes a multi-part transformation (encryption or decryption).
1304      * <p>
1305      * Processes the {@code input.remaining()} bytes in {@code input} buffer at
1306      * {@code input.position()}, and any bytes that have been buffered in
1307      * previous {@code update} calls. The transformed bytes are placed into
1308      * {@code output} buffer.
1309      * </p>
1310      *
1311      * @param input
1312      *            the input buffer.
1313      * @param output
1314      *            the output buffer.
1315      * @return the number of bytes placed into the output buffer.
1316      * @throws ShortBufferException
1317      *             if the size of the {@code output} buffer is too small.
1318      * @throws IllegalBlockSizeException
1319      *             if the size of the resulting bytes is not a multiple of the
1320      *             cipher block size.
1321      * @throws BadPaddingException
1322      *             if the padding of the data does not match the padding scheme.
1323      * @throws IllegalArgumentException
1324      *             if the input buffer and the output buffer are the same
1325      *             object.
1326      * @throws IllegalStateException
1327      *             if this cipher instance is not initialized for encryption or
1328      *             decryption.
1329      * @since Android 1.0
1330      */
doFinal(ByteBuffer input, ByteBuffer output)1331     public final int doFinal(ByteBuffer input, ByteBuffer output)
1332             throws ShortBufferException, IllegalBlockSizeException,
1333             BadPaddingException {
1334         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1335             throw new IllegalStateException(
1336                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1337         }
1338         if (input == output) {
1339             throw new IllegalArgumentException(
1340                     Messages.getString("crypto.2E")); //$NON-NLS-1$
1341         }
1342         return spiImpl.engineDoFinal(input, output);
1343     }
1344 
1345     /**
1346      * Wraps a key using this cipher instance.
1347      *
1348      * @param key
1349      *            the key to wrap.
1350      * @return the wrapped key.
1351      * @throws IllegalBlockSizeException
1352      *             if the size of the resulting bytes is not a multiple of the
1353      *             cipher block size.
1354      * @throws InvalidKeyException
1355      *             if this cipher instance can not wrap this key.
1356      * @throws IllegalStateException
1357      *             if this cipher instance is not initialized for wrapping.
1358      * @since Android 1.0
1359      */
wrap(Key key)1360     public final byte[] wrap(Key key) throws IllegalBlockSizeException,
1361             InvalidKeyException {
1362         if (mode != WRAP_MODE) {
1363             throw new IllegalStateException(
1364                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1365         }
1366         return spiImpl.engineWrap(key);
1367     }
1368 
1369     /**
1370      * Unwraps a key using this cipher instance.
1371      *
1372      * @param wrappedKey
1373      *            the wrapped key to unwrap.
1374      * @param wrappedKeyAlgorithm
1375      *            the algorithm for the wrapped key.
1376      * @param wrappedKeyType
1377      *            the type of the wrapped key (one of: {@code SECRET_KEY
1378      *            <code>, <code>PRIVATE_KEY} or {@code PUBLIC_KEY})
1379      * @return the unwrapped key
1380      * @throws InvalidKeyException
1381      *             if the {@code wrappedKey} can not be unwrapped to a key of
1382      *             type {@code wrappedKeyType} for the {@code
1383      *             wrappedKeyAlgorithm}.
1384      * @throws NoSuchAlgorithmException
1385      *             if no provider can be found that can create a key of type
1386      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
1387      * @throws IllegalStateException
1388      *             if this cipher instance is not initialized for unwrapping.
1389      * @since Android 1.0
1390      */
unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)1391     public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
1392             int wrappedKeyType) throws InvalidKeyException,
1393             NoSuchAlgorithmException {
1394         if (mode != UNWRAP_MODE) {
1395             throw new IllegalStateException(
1396                     Messages.getString("crypto.1C")); //$NON-NLS-1$
1397         }
1398         return spiImpl.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
1399                 wrappedKeyType);
1400     }
1401 
1402     /**
1403      * Returns the maximum key length for the specified transformation.
1404      *
1405      * @param transformation
1406      *            the transformation name.
1407      * @return the maximum key length, currently {@code Integer.MAX_VALUE}.
1408      * @throws NoSuchAlgorithmException
1409      *             if no provider for the specified {@code transformation} can
1410      *             be found.
1411      * @throws NullPointerException
1412      *             if {@code transformation} is {@code null}.
1413      * @since Android 1.0
1414      */
getMaxAllowedKeyLength(String transformation)1415     public static final int getMaxAllowedKeyLength(String transformation)
1416             throws NoSuchAlgorithmException {
1417         if (transformation == null) {
1418             throw new NullPointerException();
1419         }
1420         checkTransformation(transformation);
1421         //FIXME jurisdiction policy files
1422         return Integer.MAX_VALUE;
1423     }
1424 
1425     /**
1426      * Returns the maximum cipher parameter value for the specified
1427      * transformation. If there is no maximum limit, {@code null} is returned.
1428      *
1429      * @param transformation
1430      *            the transformation name.
1431      * @return a parameter spec holding the maximum value or {@code null}.
1432      *         Currently {@code null}.
1433      * @throws NoSuchAlgorithmException
1434      *             if no provider for the specified {@code transformation} can
1435      *             be found.
1436      * @throws NullPointerException
1437      *             if {@code transformation} is {@code null}.
1438      * @since Android 1.0
1439      */
getMaxAllowedParameterSpec( String transformation)1440     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
1441             String transformation) throws NoSuchAlgorithmException {
1442         if (transformation == null) {
1443             throw new NullPointerException();
1444         }
1445         checkTransformation(transformation);
1446         //FIXME jurisdiction policy files
1447         return null;
1448     }
1449 }
1450