Source for javax.crypto.Cipher

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