001    /* Cipher.java -- Interface to a cryptographic cipher.
002       Copyright (C) 2004, 2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.crypto;
040    
041    import gnu.java.security.Engine;
042    
043    import java.nio.ByteBuffer;
044    import java.nio.ReadOnlyBufferException;
045    
046    import java.security.AlgorithmParameters;
047    import java.security.InvalidAlgorithmParameterException;
048    import java.security.InvalidKeyException;
049    import java.security.Key;
050    import java.security.NoSuchAlgorithmException;
051    import java.security.NoSuchProviderException;
052    import java.security.Provider;
053    import java.security.SecureRandom;
054    import java.security.Security;
055    import java.security.cert.Certificate;
056    import java.security.cert.X509Certificate;
057    import java.security.spec.AlgorithmParameterSpec;
058    import java.util.StringTokenizer;
059    
060    /**
061     * <p>This class implements a cryptographic cipher for transforming
062     * data.</p>
063     *
064     * <p>Ciphers cannot be instantiated directly; rather one of the
065     * <code>getInstance</code> must be used to instantiate a given
066     * <i>transformation</i>, optionally with a specific provider.</p>
067     *
068     * <p>A transformation is of the form:</p>
069     *
070     * <ul>
071     * <li><i>algorithm</i>/<i>mode</i>/<i>padding</i>, or</li>
072     * <li><i>algorithm</i>
073     * </ul>
074     *
075     * <p>where <i>algorithm</i> is the base name of a cryptographic cipher
076     * (such as "AES"), <i>mode</i> is the abbreviated name of a block
077     * cipher mode (such as "CBC" for cipher block chaining mode), and
078     * <i>padding</i> is the name of a padding scheme (such as
079     * "PKCS5Padding"). If only the algorithm name is supplied, then the
080     * provider-specific default mode and padding will be used.</p>
081     *
082     * <p>An example transformation is:</p>
083     *
084     * <blockquote><code>Cipher c =
085     * Cipher.getInstance("AES/CBC/PKCS5Padding");</code></blockquote>
086     *
087     * <p>Finally, when requesting a block cipher in stream cipher mode
088     * (such as <acronym title="Advanced Encryption Standard">AES</acronym>
089     * in OFB or CFB mode) the number of bits to be processed
090     * at a time may be specified by appending it to the name of the mode;
091     * e.g. <code>"AES/OFB8/NoPadding"</code>. If no such number is
092     * specified a provider-specific default value is used.</p>
093     *
094     * @author Casey Marshall (csm@gnu.org)
095     * @see java.security.KeyGenerator
096     * @see javax.crypto.SecretKey
097     */
098    public class Cipher
099    {
100    
101      // Constants and variables.
102      // ------------------------------------------------------------------------
103    
104      private static final String SERVICE = "Cipher";
105    
106      /**
107       * The decryption operation mode.
108       */
109      public static final int DECRYPT_MODE = 2;
110    
111      /**
112       * The encryption operation mode.
113       */
114      public static final int ENCRYPT_MODE = 1;
115    
116      /**
117       * Constant for when the key to be unwrapped is a private key.
118       */
119      public static final int PRIVATE_KEY = 2;
120    
121      /**
122       * Constant for when the key to be unwrapped is a public key.
123       */
124      public static final int PUBLIC_KEY = 1;
125    
126      /**
127       * Constant for when the key to be unwrapped is a secret key.
128       */
129      public static final int SECRET_KEY = 3;
130    
131      /**
132       * The key unwrapping operation mode.
133       */
134      public static final int UNWRAP_MODE = 4;
135    
136      /**
137       * The key wrapping operation mode.
138       */
139      public static final int WRAP_MODE = 3;
140    
141      /**
142       * The uninitialized state. This state signals that any of the
143       * <code>init</code> methods have not been called, and therefore no
144       * transformations can be done.
145       */
146      private static final int INITIAL_STATE = 0;
147    
148      /** The underlying cipher service provider interface. */
149      private CipherSpi cipherSpi;
150    
151      /** The provider from which this instance came. */
152      private Provider provider;
153    
154      /** The transformation requested. */
155      private String transformation;
156    
157      /** Our current state (encrypting, wrapping, etc.) */
158      private int state;
159    
160      /**
161       * Creates a new cipher instance for the given transformation.
162       * <p>
163       * The installed providers are tried in order for an implementation, and the
164       * first appropriate instance is returned. If no installed provider can
165       * provide the implementation, an appropriate exception is thrown.
166       *
167       * @param transformation The transformation to create.
168       * @return An appropriate cipher for this transformation.
169       * @throws NoSuchAlgorithmException If no installed provider can supply the
170       *           appropriate cipher or mode.
171       * @throws NoSuchPaddingException If no installed provider can supply the
172       *           appropriate padding.
173       */
174      public static final Cipher getInstance(String transformation)
175          throws NoSuchAlgorithmException, NoSuchPaddingException
176      {
177        Provider[] p = Security.getProviders();
178        NoSuchAlgorithmException lastException = null;
179        NoSuchPaddingException lastPaddingException = null;
180        for (int i = 0; i < p.length; i++)
181          try
182            {
183              return getInstance(transformation, p[i]);
184            }
185          catch (NoSuchAlgorithmException x)
186            {
187              lastException = x;
188              lastPaddingException = null;
189            }
190          catch (NoSuchPaddingException x)
191            {
192              lastPaddingException = x;
193            }
194        if (lastPaddingException != null)
195          throw lastPaddingException;
196        if (lastException != null)
197          throw lastException;
198        throw new NoSuchAlgorithmException(transformation);
199      }
200    
201      /**
202       * Creates a new cipher instance for the given transformation and the named
203       * provider.
204       *
205       * @param transformation The transformation to create.
206       * @param provider The name of the provider to use.
207       * @return An appropriate cipher for this transformation.
208       * @throws NoSuchAlgorithmException If the provider cannot supply the
209       *           appropriate cipher or mode.
210       * @throws NoSuchProviderException If the named provider is not installed.
211       * @throws NoSuchPaddingException If the provider cannot supply the
212       *           appropriate padding.
213       * @throws IllegalArgumentException if either <code>transformation</code> or
214       *           <code>provider</code> is <code>null</code>.
215       */
216      public static final Cipher getInstance(String transformation, String provider)
217          throws NoSuchAlgorithmException, NoSuchProviderException,
218          NoSuchPaddingException
219      {
220        if (provider == null)
221          throw new IllegalArgumentException("provider MUST NOT be null");
222        Provider p = Security.getProvider(provider);
223        if (p == null)
224          throw new NoSuchProviderException(provider);
225        return getInstance(transformation, p);
226      }
227    
228      /**
229       * Creates a new cipher instance for a given transformation from a given
230       * provider.
231       *
232       * @param transformation The transformation to create.
233       * @param provider The provider to use.
234       * @return An appropriate cipher for this transformation.
235       * @throws NoSuchAlgorithmException If the given provider cannot supply the
236       *           appropriate cipher or mode.
237       * @throws NoSuchPaddingException If the given provider cannot supply the
238       *           appropriate padding scheme.
239       */
240      public static final Cipher getInstance(String transformation,
241                                             Provider provider)
242          throws NoSuchAlgorithmException, NoSuchPaddingException
243      {
244        StringBuilder sb = new StringBuilder().append("Cipher transformation [")
245            .append(transformation).append("] from provider [")
246            .append(provider).append("] ");
247        Throwable cause;
248        Object spi;
249        CipherSpi result;
250        if (transformation.indexOf('/') < 0)
251          {
252            try
253              {
254                spi = Engine.getInstance(SERVICE, transformation, provider);
255                return new Cipher((CipherSpi) spi, provider, transformation);
256              }
257            catch (Exception e)
258              {
259                if (e instanceof NoSuchAlgorithmException)
260                  throw (NoSuchAlgorithmException) e;
261                cause = e;
262              }
263          }
264        else
265          {
266            StringTokenizer tok = new StringTokenizer(transformation, "/");
267            if (tok.countTokens() != 3)
268              throw new NoSuchAlgorithmException(sb.append("is malformed").toString());
269    
270            String alg = tok.nextToken();
271            String mode = tok.nextToken();
272            String pad = tok.nextToken();
273            try
274              {
275                spi = Engine.getInstance(SERVICE, transformation, provider);
276                return new Cipher((CipherSpi) spi, provider, transformation);
277              }
278            catch (Exception e)
279              {
280                cause = e;
281              }
282    
283            try
284              {
285                spi = Engine.getInstance(SERVICE, alg + '/' + mode, provider);
286                result = (CipherSpi) spi;
287                result.engineSetPadding(pad);
288                return new Cipher(result, provider, transformation);
289              }
290            catch (Exception e)
291              {
292                if (e instanceof NoSuchPaddingException)
293                  throw (NoSuchPaddingException) e;
294                cause = e;
295              }
296    
297            try
298              {
299                spi = Engine.getInstance(SERVICE, alg + "//" + pad, provider);
300                result = (CipherSpi) spi;
301                result.engineSetMode(mode);
302                return new Cipher(result, provider, transformation);
303              }
304            catch (Exception e)
305              {
306                cause = e;
307              }
308    
309            try
310              {
311                spi = Engine.getInstance(SERVICE, alg, provider);
312                result = (CipherSpi) spi;
313                result.engineSetMode(mode);
314                result.engineSetPadding(pad);
315                return new Cipher(result, provider, transformation);
316              }
317            catch (Exception e)
318              {
319                if (e instanceof NoSuchPaddingException)
320                  throw (NoSuchPaddingException) e;
321                cause = e;
322              }
323          }
324        sb.append("could not be created");
325        NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
326        x.initCause(cause);
327        throw x;
328      }
329    
330      /**
331       * Create a cipher.
332       *
333       * @param cipherSpi The underlying implementation of the cipher.
334       * @param provider  The provider of this cipher implementation.
335       * @param transformation The transformation this cipher performs.
336       */
337      protected
338      Cipher(CipherSpi cipherSpi, Provider provider, String transformation)
339      {
340        this.cipherSpi = cipherSpi;
341        this.provider = provider;
342        this.transformation = transformation;
343        state = INITIAL_STATE;
344      }
345    
346      /**
347       * Get the name that this cipher instance was created with; this is
348       * equivalent to the "transformation" argument given to any of the
349       * {@link #getInstance()} methods.
350       *
351       * @return The cipher name.
352       */
353      public final String getAlgorithm()
354      {
355        return transformation;
356      }
357    
358      /**
359       * Return the size of blocks, in bytes, that this cipher processes.
360       *
361       * @return The block size.
362       */
363      public final int getBlockSize()
364      {
365        if (cipherSpi != null)
366          {
367            return cipherSpi.engineGetBlockSize();
368          }
369        return 1;
370      }
371    
372      /**
373       * Return the currently-operating {@link ExemptionMechanism}.
374       *
375       * @return null, currently.
376       */
377      public final ExemptionMechanism getExemptionMechanism()
378      {
379        return null;
380      }
381    
382      /**
383       * Return the <i>initialization vector</i> that this instance was
384       * initialized with.
385       *
386       * @return The IV.
387       */
388      public final byte[] getIV()
389      {
390        if (cipherSpi != null)
391          {
392            return cipherSpi.engineGetIV();
393          }
394        return null;
395      }
396    
397      /**
398       * Return the {@link java.security.AlgorithmParameters} that this
399       * instance was initialized with.
400       *
401       * @return The parameters.
402       */
403      public final AlgorithmParameters getParameters()
404      {
405        if (cipherSpi != null) {
406          return cipherSpi.engineGetParameters();
407        }
408        return null;
409      }
410    
411      /**
412       * Return this cipher's provider.
413       *
414       * @return The provider.
415       */
416      public final Provider getProvider()
417      {
418        return provider;
419      }
420    
421      /**
422       * Finishes a multi-part transformation, and returns the final
423       * transformed bytes.
424       *
425       * @return The final transformed bytes.
426       * @throws java.lang.IllegalStateException If this instance has not
427       *         been initialized, or if a <tt>doFinal</tt> call has already
428       *         been made.
429       * @throws javax.crypto.IllegalBlockSizeException If this instance has
430       *         no padding and the input is not a multiple of this cipher's
431       *         block size.
432       * @throws javax.crypto.BadPaddingException If this instance is
433       *         decrypting and the padding bytes do not match this
434       *         instance's padding scheme.
435       */
436      public final byte[] doFinal()
437        throws IllegalStateException, IllegalBlockSizeException, BadPaddingException
438      {
439        return doFinal(new byte[0], 0, 0);
440      }
441    
442      /**
443       * Finishes a multi-part transformation or does an entire
444       * transformation on the input, and returns the transformed bytes.
445       *
446       * @param input The final input bytes.
447       * @return The final transformed bytes.
448       * @throws java.lang.IllegalStateException If this instance has not
449       *         been initialized, or if a <tt>doFinal</tt> call has already
450       *         been made.
451       * @throws javax.crypto.IllegalBlockSizeException If this instance has
452       *         no padding and the input is not a multiple of this cipher's
453       *         block size.
454       * @throws javax.crypto.BadPaddingException If this instance is
455       *         decrypting and the padding bytes do not match this
456       *         instance's padding scheme.
457       */
458      public final byte[] doFinal(byte[] input)
459        throws IllegalStateException, IllegalBlockSizeException, BadPaddingException
460      {
461        return doFinal(input, 0, input.length);
462      }
463    
464      /**
465       * Finishes a multi-part transformation or does an entire
466       * transformation on the input, and returns the transformed bytes.
467       *
468       * @param input       The final input bytes.
469       * @param inputOffset The index in the input bytes to start.
470       * @param inputLength The number of bytes to read from the input.
471       * @return The final transformed bytes.
472       * @throws java.lang.IllegalStateException If this instance has not
473       *         been initialized, or if a <tt>doFinal</tt> call has already
474       *         been made.
475       * @throws javax.crypto.IllegalBlockSizeException If this instance has
476       *         no padding and the input is not a multiple of this cipher's
477       *         block size.
478       * @throws javax.crypto.BadPaddingException If this instance is
479       *         decrypting and the padding bytes do not match this
480       *         instance's padding scheme.
481       */
482      public final byte[] doFinal(byte[] input, int inputOffset, int inputLength)
483        throws IllegalStateException, IllegalBlockSizeException, BadPaddingException
484      {
485        if (cipherSpi == null)
486          {
487            byte[] b = new byte[inputLength];
488            System.arraycopy(input, inputOffset, b, 0, inputLength);
489            return b;
490          }
491        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
492          {
493            throw new IllegalStateException("neither encrypting nor decrypting");
494          }
495        return cipherSpi.engineDoFinal(input, inputOffset, inputLength);
496      }
497    
498      /**
499       * Finishes a multi-part transformation and stores the transformed
500       * bytes into the given array.
501       *
502       * @param output       The destination for the transformed bytes.
503       * @param outputOffset The offset in <tt>output</tt> to start storing
504       *        bytes.
505       * @return The number of bytes placed into the output array.
506       * @throws java.lang.IllegalStateException If this instance has not
507       *         been initialized, or if a <tt>doFinal</tt> call has already
508       *         been made.
509       * @throws javax.crypto.IllegalBlockSizeException If this instance has
510       *         no padding and the input is not a multiple of this cipher's
511       *         block size.
512       * @throws javax.crypto.BadPaddingException If this instance is
513       *         decrypting and the padding bytes do not match this
514       *         instance's padding scheme.
515       * @throws javax.crypto.ShortBufferException If the output array is
516       *         not large enough to hold the transformed bytes.
517       */
518      public final int doFinal(byte[] output, int outputOffset)
519        throws IllegalStateException, IllegalBlockSizeException, BadPaddingException,
520               ShortBufferException
521      {
522        if (cipherSpi == null)
523          {
524            return 0;
525          }
526        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
527          {
528            throw new IllegalStateException("neither encrypting nor decrypting");
529          }
530        return cipherSpi.engineDoFinal(new byte[0], 0, 0, output, outputOffset);
531      }
532    
533      /**
534       * Finishes a multi-part transformation or transforms a portion of a
535       * byte array, and stores the result in the given byte array.
536       *
537       * @param input        The input bytes.
538       * @param inputOffset  The index in <tt>input</tt> to start.
539       * @param inputLength  The number of bytes to transform.
540       * @param output       The output buffer.
541       * @param outputOffset The index in <tt>output</tt> to start.
542       * @return The number of bytes placed into the output array.
543       * @throws java.lang.IllegalStateException If this instance has not
544       *         been initialized, or if a <tt>doFinal</tt> call has already
545       *         been made.
546       * @throws javax.crypto.IllegalBlockSizeException If this instance has
547       *         no padding and the input is not a multiple of this cipher's
548       *         block size.
549       * @throws javax.crypto.BadPaddingException If this instance is
550       *         decrypting and the padding bytes do not match this
551       *         instance's padding scheme.
552       * @throws javax.crypto.ShortBufferException If the output array is
553       *         not large enough to hold the transformed bytes.
554       */
555      public final int doFinal(byte[] input, int inputOffset, int inputLength,
556                               byte[] output, int outputOffset)
557        throws IllegalStateException, IllegalBlockSizeException, BadPaddingException,
558               ShortBufferException
559      {
560        if (cipherSpi == null)
561          {
562            if (inputLength > output.length - outputOffset)
563              {
564                throw new ShortBufferException();
565              }
566            System.arraycopy(input, inputOffset, output, outputOffset, inputLength);
567            return inputLength;
568          }
569        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
570          {
571            throw new IllegalStateException("neither encrypting nor decrypting");
572          }
573        return cipherSpi.engineDoFinal(input, inputOffset, inputLength,
574                                       output, outputOffset);
575      }
576    
577      public final int doFinal(byte[] input, int inputOffset, int inputLength,
578                               byte[] output)
579        throws IllegalStateException, IllegalBlockSizeException, BadPaddingException,
580               ShortBufferException
581      {
582        return doFinal(input, inputOffset, inputLength, output, 0);
583      }
584    
585      /**
586       * Finishes a multi-part transformation with, or completely
587       * transforms, a byte buffer, and stores the result into the output
588       * buffer.
589       *
590       * @param input  The input buffer.
591       * @param output The output buffer.
592       * @return The number of bytes stored into the output buffer.
593       * @throws IllegalArgumentException If the input and output buffers
594       *  are the same object.
595       * @throws IllegalStateException If this cipher was not initialized
596       *  for encryption or decryption.
597       * @throws ReadOnlyBufferException If the output buffer is not
598       *  writable.
599       * @throws IllegalBlockSizeException If this cipher requires a total
600       *  input that is a multiple of its block size to complete this
601       *  transformation.
602       * @throws ShortBufferException If the output buffer is not large
603       *  enough to hold the transformed bytes.
604       * @throws BadPaddingException If the cipher is a block cipher with
605       *  a padding scheme, and the decrypted bytes do not end with a
606       *  valid padding.
607       * @since 1.5
608       */
609      public final int doFinal (ByteBuffer input, ByteBuffer output)
610        throws ReadOnlyBufferException, ShortBufferException,
611               BadPaddingException, IllegalBlockSizeException
612      {
613        if (input == output)
614          throw new IllegalArgumentException
615            ("input and output buffers cannot be the same");
616        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
617          throw new IllegalStateException
618            ("not initialized for encrypting or decrypting");
619        return cipherSpi.engineDoFinal (input, output);
620      }
621    
622      /**
623       * Returns the size an output buffer needs to be if this cipher is
624       * updated with a number of bytes.
625       *
626       * @param inputLength The input length.
627       * @return The output length given this input length.
628       * @throws java.lang.IllegalStateException If this instance has not
629       *         been initialized, or if a <tt>doFinal</tt> call has already
630       *         been made.
631       */
632      public final int getOutputSize(int inputLength) throws IllegalStateException
633      {
634        if (cipherSpi == null)
635          return inputLength;
636        return cipherSpi.engineGetOutputSize(inputLength);
637      }
638    
639      /**
640       * <p>Initialize this cipher with the public key from the given
641       * certificate.</p>
642       *
643       * <p>The cipher will be initialized for encryption, decryption, key
644       * wrapping, or key unwrapping, depending upon whether the
645       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
646       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
647       * respectively.</p>
648       *
649       * <p>As per the Java 1.4 specification, if <code>cert</code> is an
650       * instance of an {@link java.security.cert.X509Certificate} and its
651       * <i>key usage</i> extension field is incompatible with
652       * <code>opmode</code> then an {@link
653       * java.security.InvalidKeyException} is thrown.</p>
654       *
655       * <p>If this cipher requires any random bytes (for example for an
656       * initilization vector) than the {@link java.security.SecureRandom}
657       * with the highest priority is used as the source of these bytes.</p>
658       *
659       * <p>A call to any of the <code>init</code> methods overrides the
660       * state of the instance, and is equivalent to creating a new instance
661       * and calling its <code>init</code> method.</p>
662       *
663       * @param opmode      The operation mode to use.
664       * @param certificate The certificate.
665       * @throws java.security.InvalidKeyException If the underlying cipher
666       *         instance rejects the certificate's public key, or if the
667       *         public key cannot be used as described above.
668       */
669      public final void init(int opmode, Certificate certificate)
670        throws InvalidKeyException
671      {
672        init(opmode, certificate, new SecureRandom());
673      }
674    
675      /**
676       * <p>Initialize this cipher with the supplied key.</p>
677       *
678       * <p>The cipher will be initialized for encryption, decryption, key
679       * wrapping, or key unwrapping, depending upon whether the
680       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
681       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
682       * respectively.</p>
683       *
684       * <p>If this cipher requires any random bytes (for example for an
685       * initilization vector) than the {@link java.security.SecureRandom}
686       * with the highest priority is used as the source of these bytes.</p>
687       *
688       * <p>A call to any of the <code>init</code> methods overrides the
689       * state of the instance, and is equivalent to creating a new instance
690       * and calling its <code>init</code> method.</p>
691       *
692       * @param opmode The operation mode to use.
693       * @param key    The key.
694       * @throws java.security.InvalidKeyException If the underlying cipher
695       *         instance rejects the given key.
696       */
697      public final void init(int opmode, Key key) throws InvalidKeyException
698      {
699        if (cipherSpi != null)
700          {
701            cipherSpi.engineInit(opmode, key, new SecureRandom());
702          }
703        state = opmode;
704      }
705    
706      /**
707       * <p>Initialize this cipher with the public key from the given
708       * certificate and the specified source of randomness.</p>
709       *
710       * <p>The cipher will be initialized for encryption, decryption, key
711       * wrapping, or key unwrapping, depending upon whether the
712       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
713       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
714       * respectively.</p>
715       *
716       * <p>As per the Java 1.4 specification, if <code>cert</code> is an
717       * instance of an {@link java.security.cert.X509Certificate} and its
718       * <i>key usage</i> extension field is incompatible with
719       * <code>opmode</code> then an {@link
720       * java.security.InvalidKeyException} is thrown.</p>
721       *
722       * <p>If this cipher requires any random bytes (for example for an
723       * initilization vector) than the {@link java.security.SecureRandom}
724       * with the highest priority is used as the source of these bytes.</p>
725       *
726       * <p>A call to any of the <code>init</code> methods overrides the
727       * state of the instance, and is equivalent to creating a new instance
728       * and calling its <code>init</code> method.</p>
729       *
730       * @param opmode      The operation mode to use.
731       * @param certificate The certificate.
732       * @param random      The source of randomness.
733       * @throws java.security.InvalidKeyException If the underlying cipher
734       *         instance rejects the certificate's public key, or if the
735       *         public key cannot be used as described above.
736       */
737      public final void
738      init(int opmode, Certificate certificate, SecureRandom random)
739      throws InvalidKeyException
740      {
741        if (certificate instanceof X509Certificate)
742          {
743            boolean[] keyInfo = ((X509Certificate) certificate).getKeyUsage();
744            if (keyInfo != null)
745              {
746                switch (opmode)
747                  {
748                  case DECRYPT_MODE:
749                    if (!keyInfo[3])
750                      {
751                        throw new InvalidKeyException(
752                          "the certificate's key cannot be used for transforming data");
753                      }
754                    if (keyInfo[7])
755                      {
756                        throw new InvalidKeyException(
757                          "the certificate's key can only be used for encryption");
758                      }
759                    break;
760    
761                  case ENCRYPT_MODE:
762                    if (!keyInfo[3])
763                      {
764                        throw new InvalidKeyException(
765                          "the certificate's key cannot be used for transforming data");
766                      }
767                    if (keyInfo[8])
768                      {
769                        throw new InvalidKeyException(
770                          "the certificate's key can only be used for decryption");
771                      }
772                    break;
773    
774                  case UNWRAP_MODE:
775                    if (!keyInfo[2] || keyInfo[7])
776                      {
777                        throw new InvalidKeyException(
778                          "the certificate's key cannot be used for key unwrapping");
779                      }
780                    break;
781    
782                  case WRAP_MODE:
783                    if (!keyInfo[2] || keyInfo[8])
784                      {
785                        throw new InvalidKeyException(
786                          "the certificate's key cannot be used for key wrapping");
787                      }
788                    break;
789                  }
790              }
791          }
792        init(opmode, certificate.getPublicKey(), random);
793      }
794    
795      /**
796       * <p>Initialize this cipher with the supplied key and source of
797       * randomness.</p>
798       *
799       * <p>The cipher will be initialized for encryption, decryption, key
800       * wrapping, or key unwrapping, depending upon whether the
801       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
802       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
803       * respectively.</p>
804       *
805       * <p>A call to any of the <code>init</code> methods overrides the
806       * state of the instance, and is equivalent to creating a new instance
807       * and calling its <code>init</code> method.</p>
808       *
809       * @param opmode The operation mode to use.
810       * @param key    The key.
811       * @param random The source of randomness to use.
812       * @throws java.security.InvalidKeyException If the underlying cipher
813       *         instance rejects the given key.
814       */
815      public final void init(int opmode, Key key, SecureRandom random)
816        throws InvalidKeyException
817      {
818        if (cipherSpi != null)
819          {
820            cipherSpi.engineInit(opmode, key, random);
821          }
822        state = opmode;
823      }
824    
825      /**
826       * <p>Initialize this cipher with the supplied key and parameters.</p>
827       *
828       * <p>The cipher will be initialized for encryption, decryption, key
829       * wrapping, or key unwrapping, depending upon whether the
830       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
831       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
832       * respectively.</p>
833       *
834       * <p>If this cipher requires any random bytes (for example for an
835       * initilization vector) then the {@link java.security.SecureRandom}
836       * with the highest priority is used as the source of these bytes.</p>
837       *
838       * <p>A call to any of the <code>init</code> methods overrides the
839       * state of the instance, and is equivalent to creating a new instance
840       * and calling its <code>init</code> method.</p>
841       *
842       * @param opmode The operation mode to use.
843       * @param key    The key.
844       * @param params The algorithm parameters to initialize this instance
845       *               with.
846       * @throws java.security.InvalidKeyException If the underlying cipher
847       *         instance rejects the given key.
848       * @throws java.security.InvalidAlgorithmParameterException If the
849       *         supplied parameters are inappropriate for this cipher.
850       */
851      public final void init(int opmode, Key key, AlgorithmParameters params)
852        throws InvalidKeyException, InvalidAlgorithmParameterException
853      {
854        init(opmode, key, params, new SecureRandom());
855      }
856    
857      /**
858       * <p>Initialize this cipher with the supplied key and parameters.</p>
859       *
860       * <p>The cipher will be initialized for encryption, decryption, key
861       * wrapping, or key unwrapping, depending upon whether the
862       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
863       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
864       * respectively.</p>
865       *
866       * <p>If this cipher requires any random bytes (for example for an
867       * initilization vector) then the {@link java.security.SecureRandom}
868       * with the highest priority is used as the source of these bytes.</p>
869       *
870       * <p>A call to any of the <code>init</code> methods overrides the
871       * state of the instance, and is equivalent to creating a new instance
872       * and calling its <code>init</code> method.</p>
873       *
874       * @param opmode The operation mode to use.
875       * @param key    The key.
876       * @param params The algorithm parameters to initialize this instance
877       *               with.
878       * @throws java.security.InvalidKeyException If the underlying cipher
879       *         instance rejects the given key.
880       * @throws java.security.InvalidAlgorithmParameterException If the
881       *         supplied parameters are inappropriate for this cipher.
882       */
883      public final void init(int opmode, Key key, AlgorithmParameterSpec params)
884        throws InvalidKeyException, InvalidAlgorithmParameterException
885      {
886        init(opmode, key, params, new SecureRandom());
887      }
888    
889      /**
890       * <p>Initialize this cipher with the supplied key, parameters, and
891       * source of randomness.</p>
892       *
893       * <p>The cipher will be initialized for encryption, decryption, key
894       * wrapping, or key unwrapping, depending upon whether the
895       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
896       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
897       * respectively.</p>
898       *
899       * <p>A call to any of the <code>init</code> methods overrides the
900       * state of the instance, and is equivalent to creating a new instance
901       * and calling its <code>init</code> method.</p>
902       *
903       * @param opmode The operation mode to use.
904       * @param key    The key.
905       * @param params The algorithm parameters to initialize this instance
906       *               with.
907       * @param random The source of randomness to use.
908       * @throws java.security.InvalidKeyException If the underlying cipher
909       *         instance rejects the given key.
910       * @throws java.security.InvalidAlgorithmParameterException If the
911       *         supplied parameters are inappropriate for this cipher.
912       */
913      public final void init(int opmode, Key key, AlgorithmParameters params,
914                             SecureRandom random)
915        throws InvalidKeyException, InvalidAlgorithmParameterException
916      {
917        if (cipherSpi != null)
918          {
919            cipherSpi.engineInit(opmode, key, params, random);
920          }
921        state = opmode;
922      }
923    
924      /**
925       * <p>Initialize this cipher with the supplied key, parameters, and
926       * source of randomness.</p>
927       *
928       * <p>The cipher will be initialized for encryption, decryption, key
929       * wrapping, or key unwrapping, depending upon whether the
930       * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link
931       * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE},
932       * respectively.</p>
933       *
934       * <p>A call to any of the <code>init</code> methods overrides the
935       * state of the instance, and is equivalent to creating a new instance
936       * and calling its <code>init</code> method.</p>
937       *
938       * @param opmode The operation mode to use.
939       * @param key    The key.
940       * @param params The algorithm parameters to initialize this instance
941       *               with.
942       * @param random The source of randomness to use.
943       * @throws java.security.InvalidKeyException If the underlying cipher
944       *         instance rejects the given key.
945       * @throws java.security.InvalidAlgorithmParameterException If the
946       *         supplied parameters are inappropriate for this cipher.
947       */
948      public final void init(int opmode, Key key, AlgorithmParameterSpec params,
949                             SecureRandom random)
950        throws InvalidKeyException, InvalidAlgorithmParameterException
951      {
952        if (cipherSpi != null)
953          {
954            cipherSpi.engineInit(opmode, key, params, random);
955          }
956        state = opmode;
957      }
958    
959      /**
960       * Unwrap a previously-wrapped key.
961       *
962       * @param wrappedKey          The wrapped key.
963       * @param wrappedKeyAlgorithm The algorithm with which the key was
964       *        wrapped.
965       * @param wrappedKeyType      The type of key (public, private, or
966       *        secret) that this wrapped key respresents.
967       * @return The unwrapped key.
968       * @throws java.lang.IllegalStateException If this instance has not be
969       *         initialized for unwrapping.
970       * @throws java.security.InvalidKeyException If <code>wrappedKey</code>
971       *         is not a wrapped key, if the algorithm cannot unwrap this
972       *         key, or if the unwrapped key's type differs from the
973       *         specified type.
974       * @throws java.security.NoSuchAlgorithmException If
975       *         <code>wrappedKeyAlgorithm</code> is not a valid algorithm
976       *         name.
977       */
978      public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
979                              int wrappedKeyType)
980        throws IllegalStateException, InvalidKeyException, NoSuchAlgorithmException
981      {
982        if (cipherSpi == null)
983          {
984            return null;
985          }
986        if (state != UNWRAP_MODE)
987          {
988            throw new IllegalStateException("instance is not for unwrapping");
989          }
990        return cipherSpi.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
991                                      wrappedKeyType);
992      }
993    
994      /**
995       * Continue a multi-part transformation on an entire byte array,
996       * returning the transformed bytes.
997       *
998       * @param input The input bytes.
999       * @return The transformed bytes.
1000       * @throws java.lang.IllegalStateException If this cipher was not
1001       *         initialized for encryption or decryption.
1002       */
1003      public final byte[] update(byte[] input) throws IllegalStateException
1004      {
1005        return update(input, 0, input.length);
1006      }
1007    
1008      /**
1009       * Continue a multi-part transformation on part of a byte array,
1010       * returning the transformed bytes.
1011       *
1012       * @param input       The input bytes.
1013       * @param inputOffset The index in the input to start.
1014       * @param inputLength The number of bytes to transform.
1015       * @return The transformed bytes.
1016       * @throws java.lang.IllegalStateException If this cipher was not
1017       *         initialized for encryption or decryption.
1018       */
1019      public final byte[] update(byte[] input, int inputOffset, int inputLength)
1020        throws IllegalStateException
1021      {
1022        if (cipherSpi == null)
1023          {
1024            byte[] b = new byte[inputLength];
1025            System.arraycopy(input, inputOffset, b, 0, inputLength);
1026            return b;
1027          }
1028        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
1029          {
1030            throw new IllegalStateException(
1031              "cipher is not for encrypting or decrypting");
1032          }
1033        return cipherSpi.engineUpdate(input, inputOffset, inputLength);
1034      }
1035    
1036      /**
1037       * Continue a multi-part transformation on part of a byte array,
1038       * placing the transformed bytes into the given array.
1039       *
1040       * @param input       The input bytes.
1041       * @param inputOffset The index in the input to start.
1042       * @param inputLength The number of bytes to transform.
1043       * @param output      The output byte array.
1044       * @return The number of transformed bytes.
1045       * @throws java.lang.IllegalStateException If this cipher was not
1046       *         initialized for encryption or decryption.
1047       * @throws javax.security.ShortBufferException If there is not enough
1048       *         room in the output array to hold the transformed bytes.
1049       */
1050      public final int update(byte[] input, int inputOffset, int inputLength,
1051                              byte[] output)
1052        throws IllegalStateException, ShortBufferException
1053      {
1054        return update(input, inputOffset, inputLength, output, 0);
1055      }
1056    
1057      /**
1058       * Continue a multi-part transformation on part of a byte array,
1059       * placing the transformed bytes into the given array.
1060       *
1061       * @param input        The input bytes.
1062       * @param inputOffset  The index in the input to start.
1063       * @param inputLength  The number of bytes to transform.
1064       * @param output       The output byte array.
1065       * @param outputOffset The index in the output array to start.
1066       * @return The number of transformed bytes.
1067       * @throws java.lang.IllegalStateException If this cipher was not
1068       *         initialized for encryption or decryption.
1069       * @throws javax.security.ShortBufferException If there is not enough
1070       *         room in the output array to hold the transformed bytes.
1071       */
1072      public final int update(byte[] input, int inputOffset, int inputLength,
1073                              byte[] output, int outputOffset)
1074        throws IllegalStateException, ShortBufferException
1075      {
1076        if (cipherSpi == null)
1077          {
1078            if (inputLength > output.length - outputOffset)
1079              {
1080                throw new ShortBufferException();
1081              }
1082            System.arraycopy(input, inputOffset, output, outputOffset, inputLength);
1083            return inputLength;
1084          }
1085        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
1086          {
1087            throw new IllegalStateException(
1088              "cipher is not for encrypting or decrypting");
1089          }
1090        return cipherSpi.engineUpdate(input, inputOffset, inputLength,
1091                                      output, outputOffset);
1092      }
1093    
1094      /**
1095       * Continue a multi-part transformation on a byte buffer, storing
1096       * the transformed bytes into another buffer.
1097       *
1098       * @param input  The input buffer.
1099       * @param output The output buffer.
1100       * @return The number of bytes stored in <i>output</i>.
1101       * @throws IllegalArgumentException If the two buffers are the same
1102       *  object.
1103       * @throws IllegalStateException If this cipher was not initialized
1104       *  for encrypting or decrypting.
1105       * @throws ReadOnlyBufferException If the output buffer is not
1106       *  writable.
1107       * @throws ShortBufferException If the output buffer does not have
1108       *  enough available space for the transformed bytes.
1109       * @since 1.5
1110       */
1111      public final int update (ByteBuffer input, ByteBuffer output)
1112        throws ReadOnlyBufferException, ShortBufferException
1113      {
1114        if (input == output)
1115          throw new IllegalArgumentException
1116            ("input and output buffers must be different");
1117        if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
1118          throw new IllegalStateException
1119            ("not initialized for encryption or decryption");
1120        return cipherSpi.engineUpdate (input, output);
1121      }
1122    
1123      /**
1124       * Wrap a key.
1125       *
1126       * @param key The key to wrap.
1127       * @return The wrapped key.
1128       * @throws java.lang.IllegalStateException If this instance was not
1129       *         initialized for key wrapping.
1130       * @throws javax.crypto.IllegalBlockSizeException If this instance has
1131       *         no padding and the key is not a multiple of the block size.
1132       * @throws java.security.InvalidKeyException If this instance cannot
1133       *         wrap this key.
1134       */
1135      public final byte[] wrap(Key key)
1136        throws IllegalStateException, IllegalBlockSizeException, InvalidKeyException
1137      {
1138        if (cipherSpi == null)
1139          {
1140            return null;
1141          }
1142        if (state != WRAP_MODE)
1143          {
1144            throw new IllegalStateException("instance is not for key wrapping");
1145          }
1146        return cipherSpi.engineWrap(key);
1147      }
1148    }