Source for javax.crypto.Cipher

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