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