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:    * 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: }