Source for javax.crypto.Cipher

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