| /* Cipher.java -- Interface to a cryptographic cipher. |
| Copyright (C) 2004, 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package javax.crypto; |
| |
| import gnu.java.security.Engine; |
| |
| import java.nio.ByteBuffer; |
| import java.nio.ReadOnlyBufferException; |
| |
| import java.security.AlgorithmParameters; |
| import java.security.InvalidAlgorithmParameterException; |
| import java.security.InvalidKeyException; |
| import java.security.Key; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.Provider; |
| import java.security.SecureRandom; |
| import java.security.Security; |
| import java.security.cert.Certificate; |
| import java.security.cert.X509Certificate; |
| import java.security.spec.AlgorithmParameterSpec; |
| import java.util.StringTokenizer; |
| |
| /** |
| * <p>This class implements a cryptographic cipher for transforming |
| * data.</p> |
| * |
| * <p>Ciphers cannot be instantiated directly; rather one of the |
| * <code>getInstance</code> must be used to instantiate a given |
| * <i>transformation</i>, optionally with a specific provider.</p> |
| * |
| * <p>A transformation is of the form:</p> |
| * |
| * <ul> |
| * <li><i>algorithm</i>/<i>mode</i>/<i>padding</i>, or</li> |
| * <li><i>algorithm</i> |
| * </ul> |
| * |
| * <p>where <i>algorithm</i> is the base name of a cryptographic cipher |
| * (such as "AES"), <i>mode</i> is the abbreviated name of a block |
| * cipher mode (such as "CBC" for cipher block chaining mode), and |
| * <i>padding</i> is the name of a padding scheme (such as |
| * "PKCS5Padding"). If only the algorithm name is supplied, then the |
| * provider-specific default mode and padding will be used.</p> |
| * |
| * <p>An example transformation is:</p> |
| * |
| * <blockquote><code>Cipher c = |
| * Cipher.getInstance("AES/CBC/PKCS5Padding");</code></blockquote> |
| * |
| * <p>Finally, when requesting a block cipher in stream cipher mode |
| * (such as <acronym title="Advanced Encryption Standard">AES</acronym> |
| * in OFB or CFB mode) the number of bits to be processed |
| * at a time may be specified by appending it to the name of the mode; |
| * e.g. <code>"AES/OFB8/NoPadding"</code>. If no such number is |
| * specified a provider-specific default value is used.</p> |
| * |
| * @author Casey Marshall (csm@gnu.org) |
| * @see java.security.KeyGenerator |
| * @see javax.crypto.SecretKey |
| */ |
| public class Cipher |
| { |
| |
| // Constants and variables. |
| // ------------------------------------------------------------------------ |
| |
| private static final String SERVICE = "Cipher"; |
| |
| /** |
| * The decryption operation mode. |
| */ |
| public static final int DECRYPT_MODE = 2; |
| |
| /** |
| * The encryption operation mode. |
| */ |
| public static final int ENCRYPT_MODE = 1; |
| |
| /** |
| * Constant for when the key to be unwrapped is a private key. |
| */ |
| public static final int PRIVATE_KEY = 2; |
| |
| /** |
| * Constant for when the key to be unwrapped is a public key. |
| */ |
| public static final int PUBLIC_KEY = 1; |
| |
| /** |
| * Constant for when the key to be unwrapped is a secret key. |
| */ |
| public static final int SECRET_KEY = 3; |
| |
| /** |
| * The key unwrapping operation mode. |
| */ |
| public static final int UNWRAP_MODE = 4; |
| |
| /** |
| * The key wrapping operation mode. |
| */ |
| public static final int WRAP_MODE = 3; |
| |
| /** |
| * The uninitialized state. This state signals that any of the |
| * <code>init</code> methods have not been called, and therefore no |
| * transformations can be done. |
| */ |
| private static final int INITIAL_STATE = 0; |
| |
| /** The underlying cipher service provider interface. */ |
| private CipherSpi cipherSpi; |
| |
| /** The provider from which this instance came. */ |
| private Provider provider; |
| |
| /** The transformation requested. */ |
| private String transformation; |
| |
| /** Our current state (encrypting, wrapping, etc.) */ |
| private int state; |
| |
| |
| // Class methods. |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * <p>Creates a new cipher instance for the given transformation.</p> |
| * |
| * <p>The installed providers are tried in order for an |
| * implementation, and the first appropriate instance is returned. If |
| * no installed provider can provide the implementation, an |
| * appropriate exception is thrown.</p> |
| * |
| * @param transformation The transformation to create. |
| * @return An appropriate cipher for this transformation. |
| * @throws java.security.NoSuchAlgorithmException If no installed |
| * provider can supply the appropriate cipher or mode. |
| * @throws javax.crypto.NoSuchPaddingException If no installed |
| * provider can supply the appropriate padding. |
| */ |
| public static final Cipher getInstance(String transformation) |
| throws NoSuchAlgorithmException, NoSuchPaddingException |
| { |
| Provider[] providers = Security.getProviders(); |
| NoSuchPaddingException ex = null; |
| String msg = ""; |
| for (int i = 0; i < providers.length; i++) |
| { |
| try |
| { |
| return getInstance(transformation, providers[i]); |
| } |
| catch (NoSuchAlgorithmException nsae) |
| { |
| msg = nsae.getMessage(); |
| ex = null; |
| } |
| catch (NoSuchPaddingException nspe) |
| { |
| ex = nspe; |
| } |
| } |
| if (ex != null) |
| { |
| throw ex; |
| } |
| throw new NoSuchAlgorithmException(msg); |
| } |
| |
| /** |
| * <p>Creates a new cipher instance for the given transformation and |
| * the named provider.</p> |
| * |
| * @param transformation The transformation to create. |
| * @param provider The name of the provider to use. |
| * @return An appropriate cipher for this transformation. |
| * @throws java.security.NoSuchAlgorithmException If the provider cannot |
| * supply the appropriate cipher or mode. |
| * @throws java.security.NoSuchProviderException If the named provider |
| * is not installed. |
| * @throws javax.crypto.NoSuchPaddingException If the provider cannot |
| * supply the appropriate padding. |
| */ |
| public static final Cipher getInstance(String transformation, String provider) |
| throws NoSuchAlgorithmException, NoSuchProviderException, |
| NoSuchPaddingException |
| { |
| Provider p = Security.getProvider(provider); |
| if (p == null) |
| { |
| throw new NoSuchProviderException(provider); |
| } |
| return getInstance(transformation, p); |
| } |
| |
| /** |
| * Creates a new cipher instance for the given transform and the given |
| * provider. |
| * |
| * @param transformation The transformation to create. |
| * @param provider The provider to use. |
| * @return An appropriate cipher for this transformation. |
| * @throws java.security.NoSuchAlgorithmException If the given |
| * provider cannot supply the appropriate cipher or mode. |
| * @throws javax.crypto.NoSuchPaddingException If the given |
| * provider cannot supply the appropriate padding scheme. |
| */ |
| public static final Cipher getInstance(String transformation, Provider provider) |
| throws NoSuchAlgorithmException, NoSuchPaddingException |
| { |
| CipherSpi result = null; |
| String key = null; |
| String alg = null, mode = null, pad = null; |
| String msg = ""; |
| if (transformation.indexOf('/') < 0) |
| { |
| try |
| { |
| result = (CipherSpi) Engine.getInstance(SERVICE, transformation, |
| provider); |
| return new Cipher(result, provider, transformation); |
| } |
| catch (Exception e) |
| { |
| msg = e.getMessage(); |
| } |
| } |
| else |
| { |
| StringTokenizer tok = new StringTokenizer(transformation, "/"); |
| if (tok.countTokens() != 3) |
| { |
| throw new NoSuchAlgorithmException("badly formed transformation"); |
| } |
| alg = tok.nextToken(); |
| mode = tok.nextToken(); |
| pad = tok.nextToken(); |
| try |
| { |
| result = (CipherSpi) Engine.getInstance(SERVICE, transformation, |
| provider); |
| return new Cipher(result, provider, transformation); |
| } |
| catch (Exception e) |
| { |
| msg = e.getMessage(); |
| } |
| try |
| { |
| result = (CipherSpi) Engine.getInstance(SERVICE, alg + '/' + mode, |
| provider); |
| result.engineSetPadding(pad); |
| return new Cipher(result, provider, transformation); |
| } |
| catch (Exception e) |
| { |
| if (e instanceof NoSuchPaddingException) |
| { |
| throw (NoSuchPaddingException) e; |
| } |
| msg = e.getMessage(); |
| } |
| try |
| { |
| result = (CipherSpi) Engine.getInstance(SERVICE, alg + "//" + pad, |
| provider); |
| result.engineSetMode(mode); |
| return new Cipher(result, provider, transformation); |
| } |
| catch (Exception e) |
| { |
| msg = e.getMessage(); |
| } |
| try |
| { |
| result = (CipherSpi) Engine.getInstance(SERVICE, alg, provider); |
| result.engineSetMode(mode); |
| result.engineSetPadding(pad); |
| return new Cipher(result, provider, transformation); |
| } |
| catch (Exception e) |
| { |
| if (e instanceof NoSuchPaddingException) |
| { |
| throw (NoSuchPaddingException) e; |
| } |
| msg = e.getMessage(); |
| } |
| } |
| throw new NoSuchAlgorithmException(transformation + ": " + msg); |
| } |
| |
| // Constructor. |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Create a cipher. |
| * |
| * @param cipherSpi The underlying implementation of the cipher. |
| * @param provider The provider of this cipher implementation. |
| * @param transformation The transformation this cipher performs. |
| */ |
| protected |
| Cipher(CipherSpi cipherSpi, Provider provider, String transformation) |
| { |
| this.cipherSpi = cipherSpi; |
| this.provider = provider; |
| this.transformation = transformation; |
| state = INITIAL_STATE; |
| } |
| |
| // Public instance methods. |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Get the name that this cipher instance was created with; this is |
| * equivalent to the "transformation" argument given to any of the |
| * {@link #getInstance()} methods. |
| * |
| * @return The cipher name. |
| */ |
| public final String getAlgorithm() |
| { |
| return transformation; |
| } |
| |
| /** |
| * Return the size of blocks, in bytes, that this cipher processes. |
| * |
| * @return The block size. |
| */ |
| public final int getBlockSize() |
| { |
| if (cipherSpi != null) |
| { |
| return cipherSpi.engineGetBlockSize(); |
| } |
| return 1; |
| } |
| |
| /** |
| * Return the currently-operating {@link ExemptionMechanism}. |
| * |
| * @return null, currently. |
| */ |
| public final ExemptionMechanism getExemptionMechanism() |
| { |
| return null; |
| } |
| |
| /** |
| * Return the <i>initialization vector</i> that this instance was |
| * initialized with. |
| * |
| * @return The IV. |
| */ |
| public final byte[] getIV() |
| { |
| if (cipherSpi != null) |
| { |
| return cipherSpi.engineGetIV(); |
| } |
| return null; |
| } |
| |
| /** |
| * Return the {@link java.security.AlgorithmParameters} that this |
| * instance was initialized with. |
| * |
| * @return The parameters. |
| */ |
| public final AlgorithmParameters getParameters() |
| { |
| if (cipherSpi != null) { |
| return cipherSpi.engineGetParameters(); |
| } |
| return null; |
| } |
| |
| /** |
| * Return this cipher's provider. |
| * |
| * @return The provider. |
| */ |
| public final Provider getProvider() |
| { |
| return provider; |
| } |
| |
| /** |
| * Finishes a multi-part transformation, and returns the final |
| * transformed bytes. |
| * |
| * @return The final transformed bytes. |
| * @throws java.lang.IllegalStateException If this instance has not |
| * been initialized, or if a <tt>doFinal</tt> call has already |
| * been made. |
| * @throws javax.crypto.IllegalBlockSizeException If this instance has |
| * no padding and the input is not a multiple of this cipher's |
| * block size. |
| * @throws javax.crypto.BadPaddingException If this instance is |
| * decrypting and the padding bytes do not match this |
| * instance's padding scheme. |
| */ |
| public final byte[] doFinal() |
| throws IllegalStateException, IllegalBlockSizeException, BadPaddingException |
| { |
| return doFinal(new byte[0], 0, 0); |
| } |
| |
| /** |
| * Finishes a multi-part transformation or does an entire |
| * transformation on the input, and returns the transformed bytes. |
| * |
| * @param input The final input bytes. |
| * @return The final transformed bytes. |
| * @throws java.lang.IllegalStateException If this instance has not |
| * been initialized, or if a <tt>doFinal</tt> call has already |
| * been made. |
| * @throws javax.crypto.IllegalBlockSizeException If this instance has |
| * no padding and the input is not a multiple of this cipher's |
| * block size. |
| * @throws javax.crypto.BadPaddingException If this instance is |
| * decrypting and the padding bytes do not match this |
| * instance's padding scheme. |
| */ |
| public final byte[] doFinal(byte[] input) |
| throws IllegalStateException, IllegalBlockSizeException, BadPaddingException |
| { |
| return doFinal(input, 0, input.length); |
| } |
| |
| /** |
| * Finishes a multi-part transformation or does an entire |
| * transformation on the input, and returns the transformed bytes. |
| * |
| * @param input The final input bytes. |
| * @param inputOffset The index in the input bytes to start. |
| * @param inputLength The number of bytes to read from the input. |
| * @return The final transformed bytes. |
| * @throws java.lang.IllegalStateException If this instance has not |
| * been initialized, or if a <tt>doFinal</tt> call has already |
| * been made. |
| * @throws javax.crypto.IllegalBlockSizeException If this instance has |
| * no padding and the input is not a multiple of this cipher's |
| * block size. |
| * @throws javax.crypto.BadPaddingException If this instance is |
| * decrypting and the padding bytes do not match this |
| * instance's padding scheme. |
| */ |
| public final byte[] doFinal(byte[] input, int inputOffset, int inputLength) |
| throws IllegalStateException, IllegalBlockSizeException, BadPaddingException |
| { |
| if (cipherSpi == null) |
| { |
| byte[] b = new byte[inputLength]; |
| System.arraycopy(input, inputOffset, b, 0, inputLength); |
| return b; |
| } |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| { |
| throw new IllegalStateException("neither encrypting nor decrypting"); |
| } |
| return cipherSpi.engineDoFinal(input, inputOffset, inputLength); |
| } |
| |
| /** |
| * Finishes a multi-part transformation and stores the transformed |
| * bytes into the given array. |
| * |
| * @param output The destination for the transformed bytes. |
| * @param outputOffset The offset in <tt>output</tt> to start storing |
| * bytes. |
| * @return The number of bytes placed into the output array. |
| * @throws java.lang.IllegalStateException If this instance has not |
| * been initialized, or if a <tt>doFinal</tt> call has already |
| * been made. |
| * @throws javax.crypto.IllegalBlockSizeException If this instance has |
| * no padding and the input is not a multiple of this cipher's |
| * block size. |
| * @throws javax.crypto.BadPaddingException If this instance is |
| * decrypting and the padding bytes do not match this |
| * instance's padding scheme. |
| * @throws javax.crypto.ShortBufferException If the output array is |
| * not large enough to hold the transformed bytes. |
| */ |
| public final int doFinal(byte[] output, int outputOffset) |
| throws IllegalStateException, IllegalBlockSizeException, BadPaddingException, |
| ShortBufferException |
| { |
| if (cipherSpi == null) |
| { |
| return 0; |
| } |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| { |
| throw new IllegalStateException("neither encrypting nor decrypting"); |
| } |
| return cipherSpi.engineDoFinal(new byte[0], 0, 0, output, outputOffset); |
| } |
| |
| /** |
| * Finishes a multi-part transformation or transforms a portion of a |
| * byte array, and stores the result in the given byte array. |
| * |
| * @param input The input bytes. |
| * @param inputOffset The index in <tt>input</tt> to start. |
| * @param inputLength The number of bytes to transform. |
| * @param output The output buffer. |
| * @param outputOffset The index in <tt>output</tt> to start. |
| * @return The number of bytes placed into the output array. |
| * @throws java.lang.IllegalStateException If this instance has not |
| * been initialized, or if a <tt>doFinal</tt> call has already |
| * been made. |
| * @throws javax.crypto.IllegalBlockSizeException If this instance has |
| * no padding and the input is not a multiple of this cipher's |
| * block size. |
| * @throws javax.crypto.BadPaddingException If this instance is |
| * decrypting and the padding bytes do not match this |
| * instance's padding scheme. |
| * @throws javax.crypto.ShortBufferException If the output array is |
| * not large enough to hold the transformed bytes. |
| */ |
| public final int doFinal(byte[] input, int inputOffset, int inputLength, |
| byte[] output, int outputOffset) |
| throws IllegalStateException, IllegalBlockSizeException, BadPaddingException, |
| ShortBufferException |
| { |
| if (cipherSpi == null) |
| { |
| if (inputLength > output.length - outputOffset) |
| { |
| throw new ShortBufferException(); |
| } |
| System.arraycopy(input, inputOffset, output, outputOffset, inputLength); |
| return inputLength; |
| } |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| { |
| throw new IllegalStateException("neither encrypting nor decrypting"); |
| } |
| return cipherSpi.engineDoFinal(input, inputOffset, inputLength, |
| output, outputOffset); |
| } |
| |
| public final int doFinal(byte[] input, int inputOffset, int inputLength, |
| byte[] output) |
| throws IllegalStateException, IllegalBlockSizeException, BadPaddingException, |
| ShortBufferException |
| { |
| return doFinal(input, inputOffset, inputLength, output, 0); |
| } |
| |
| /** |
| * Finishes a multi-part transformation with, or completely |
| * transforms, a byte buffer, and stores the result into the output |
| * buffer. |
| * |
| * @param input The input buffer. |
| * @param output The output buffer. |
| * @return The number of bytes stored into the output buffer. |
| * @throws IllegalArgumentException If the input and output buffers |
| * are the same object. |
| * @throws IllegalStateException If this cipher was not initialized |
| * for encryption or decryption. |
| * @throws ReadOnlyBufferException If the output buffer is not |
| * writable. |
| * @throws IllegalBlockSizeException If this cipher requires a total |
| * input that is a multiple of its block size to complete this |
| * transformation. |
| * @throws ShortBufferException If the output buffer is not large |
| * enough to hold the transformed bytes. |
| * @throws BadPaddingException If the cipher is a block cipher with |
| * a padding scheme, and the decrypted bytes do not end with a |
| * valid padding. |
| * @since 1.5 |
| */ |
| public final int doFinal (ByteBuffer input, ByteBuffer output) |
| throws ReadOnlyBufferException, ShortBufferException, |
| BadPaddingException, IllegalBlockSizeException |
| { |
| if (input == output) |
| throw new IllegalArgumentException |
| ("input and output buffers cannot be the same"); |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| throw new IllegalStateException |
| ("not initialized for encrypting or decrypting"); |
| return cipherSpi.engineDoFinal (input, output); |
| } |
| |
| /** |
| * Returns the size an output buffer needs to be if this cipher is |
| * updated with a number of bytes. |
| * |
| * @param inputLength The input length. |
| * @return The output length given this input length. |
| * @throws java.lang.IllegalStateException If this instance has not |
| * been initialized, or if a <tt>doFinal</tt> call has already |
| * been made. |
| */ |
| public final int getOutputSize(int inputLength) throws IllegalStateException |
| { |
| if (cipherSpi == null) |
| return inputLength; |
| return cipherSpi.engineGetOutputSize(inputLength); |
| } |
| |
| /** |
| * <p>Initialize this cipher with the public key from the given |
| * certificate.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>As per the Java 1.4 specification, if <code>cert</code> is an |
| * instance of an {@link java.security.cert.X509Certificate} and its |
| * <i>key usage</i> extension field is incompatible with |
| * <code>opmode</code> then an {@link |
| * java.security.InvalidKeyException} is thrown.</p> |
| * |
| * <p>If this cipher requires any random bytes (for example for an |
| * initilization vector) than the {@link java.security.SecureRandom} |
| * with the highest priority is used as the source of these bytes.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param certificate The certificate. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the certificate's public key, or if the |
| * public key cannot be used as described above. |
| */ |
| public final void init(int opmode, Certificate certificate) |
| throws InvalidKeyException |
| { |
| init(opmode, certificate, new SecureRandom()); |
| } |
| |
| /** |
| * <p>Initialize this cipher with the supplied key.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>If this cipher requires any random bytes (for example for an |
| * initilization vector) than the {@link java.security.SecureRandom} |
| * with the highest priority is used as the source of these bytes.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param key The key. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the given key. |
| */ |
| public final void init(int opmode, Key key) throws InvalidKeyException |
| { |
| if (cipherSpi != null) |
| { |
| cipherSpi.engineInit(opmode, key, new SecureRandom()); |
| } |
| state = opmode; |
| } |
| |
| /** |
| * <p>Initialize this cipher with the public key from the given |
| * certificate and the specified source of randomness.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>As per the Java 1.4 specification, if <code>cert</code> is an |
| * instance of an {@link java.security.cert.X509Certificate} and its |
| * <i>key usage</i> extension field is incompatible with |
| * <code>opmode</code> then an {@link |
| * java.security.InvalidKeyException} is thrown.</p> |
| * |
| * <p>If this cipher requires any random bytes (for example for an |
| * initilization vector) than the {@link java.security.SecureRandom} |
| * with the highest priority is used as the source of these bytes.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param certificate The certificate. |
| * @param random The source of randomness. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the certificate's public key, or if the |
| * public key cannot be used as described above. |
| */ |
| public final void |
| init(int opmode, Certificate certificate, SecureRandom random) |
| throws InvalidKeyException |
| { |
| if (certificate instanceof X509Certificate) |
| { |
| boolean[] keyInfo = ((X509Certificate) certificate).getKeyUsage(); |
| if (keyInfo != null) |
| { |
| switch (opmode) |
| { |
| case DECRYPT_MODE: |
| if (!keyInfo[3]) |
| { |
| throw new InvalidKeyException( |
| "the certificate's key cannot be used for transforming data"); |
| } |
| if (keyInfo[7]) |
| { |
| throw new InvalidKeyException( |
| "the certificate's key can only be used for encryption"); |
| } |
| break; |
| |
| case ENCRYPT_MODE: |
| if (!keyInfo[3]) |
| { |
| throw new InvalidKeyException( |
| "the certificate's key cannot be used for transforming data"); |
| } |
| if (keyInfo[8]) |
| { |
| throw new InvalidKeyException( |
| "the certificate's key can only be used for decryption"); |
| } |
| break; |
| |
| case UNWRAP_MODE: |
| if (!keyInfo[2] || keyInfo[7]) |
| { |
| throw new InvalidKeyException( |
| "the certificate's key cannot be used for key unwrapping"); |
| } |
| break; |
| |
| case WRAP_MODE: |
| if (!keyInfo[2] || keyInfo[8]) |
| { |
| throw new InvalidKeyException( |
| "the certificate's key cannot be used for key wrapping"); |
| } |
| break; |
| } |
| } |
| } |
| init(opmode, certificate.getPublicKey(), random); |
| } |
| |
| /** |
| * <p>Initialize this cipher with the supplied key and source of |
| * randomness.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param key The key. |
| * @param random The source of randomness to use. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the given key. |
| */ |
| public final void init(int opmode, Key key, SecureRandom random) |
| throws InvalidKeyException |
| { |
| if (cipherSpi != null) |
| { |
| cipherSpi.engineInit(opmode, key, random); |
| } |
| state = opmode; |
| } |
| |
| /** |
| * <p>Initialize this cipher with the supplied key and parameters.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>If this cipher requires any random bytes (for example for an |
| * initilization vector) then the {@link java.security.SecureRandom} |
| * with the highest priority is used as the source of these bytes.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param key The key. |
| * @param params The algorithm parameters to initialize this instance |
| * with. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the given key. |
| * @throws java.security.InvalidAlgorithmParameterException If the |
| * supplied parameters are inappropriate for this cipher. |
| */ |
| public final void init(int opmode, Key key, AlgorithmParameters params) |
| throws InvalidKeyException, InvalidAlgorithmParameterException |
| { |
| init(opmode, key, params, new SecureRandom()); |
| } |
| |
| /** |
| * <p>Initialize this cipher with the supplied key and parameters.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>If this cipher requires any random bytes (for example for an |
| * initilization vector) then the {@link java.security.SecureRandom} |
| * with the highest priority is used as the source of these bytes.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param key The key. |
| * @param params The algorithm parameters to initialize this instance |
| * with. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the given key. |
| * @throws java.security.InvalidAlgorithmParameterException If the |
| * supplied parameters are inappropriate for this cipher. |
| */ |
| public final void init(int opmode, Key key, AlgorithmParameterSpec params) |
| throws InvalidKeyException, InvalidAlgorithmParameterException |
| { |
| init(opmode, key, params, new SecureRandom()); |
| } |
| |
| /** |
| * <p>Initialize this cipher with the supplied key, parameters, and |
| * source of randomness.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param key The key. |
| * @param params The algorithm parameters to initialize this instance |
| * with. |
| * @param random The source of randomness to use. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the given key. |
| * @throws java.security.InvalidAlgorithmParameterException If the |
| * supplied parameters are inappropriate for this cipher. |
| */ |
| public final void init(int opmode, Key key, AlgorithmParameters params, |
| SecureRandom random) |
| throws InvalidKeyException, InvalidAlgorithmParameterException |
| { |
| if (cipherSpi != null) |
| { |
| cipherSpi.engineInit(opmode, key, params, random); |
| } |
| state = opmode; |
| } |
| |
| /** |
| * <p>Initialize this cipher with the supplied key, parameters, and |
| * source of randomness.</p> |
| * |
| * <p>The cipher will be initialized for encryption, decryption, key |
| * wrapping, or key unwrapping, depending upon whether the |
| * <code>opmode</code> argument is {@link #ENCRYPT_MODE}, {@link |
| * #DECRYPT_MODE}, {@link #WRAP_MODE}, or {@link #UNWRAP_MODE}, |
| * respectively.</p> |
| * |
| * <p>A call to any of the <code>init</code> methods overrides the |
| * state of the instance, and is equivalent to creating a new instance |
| * and calling its <code>init</code> method.</p> |
| * |
| * @param opmode The operation mode to use. |
| * @param key The key. |
| * @param params The algorithm parameters to initialize this instance |
| * with. |
| * @param random The source of randomness to use. |
| * @throws java.security.InvalidKeyException If the underlying cipher |
| * instance rejects the given key. |
| * @throws java.security.InvalidAlgorithmParameterException If the |
| * supplied parameters are inappropriate for this cipher. |
| */ |
| public final void init(int opmode, Key key, AlgorithmParameterSpec params, |
| SecureRandom random) |
| throws InvalidKeyException, InvalidAlgorithmParameterException |
| { |
| if (cipherSpi != null) |
| { |
| cipherSpi.engineInit(opmode, key, params, random); |
| } |
| state = opmode; |
| } |
| |
| /** |
| * Unwrap a previously-wrapped key. |
| * |
| * @param wrappedKey The wrapped key. |
| * @param wrappedKeyAlgorithm The algorithm with which the key was |
| * wrapped. |
| * @param wrappedKeyType The type of key (public, private, or |
| * secret) that this wrapped key respresents. |
| * @return The unwrapped key. |
| * @throws java.lang.IllegalStateException If this instance has not be |
| * initialized for unwrapping. |
| * @throws java.security.InvalidKeyException If <code>wrappedKey</code> |
| * is not a wrapped key, if the algorithm cannot unwrap this |
| * key, or if the unwrapped key's type differs from the |
| * specified type. |
| * @throws java.security.NoSuchAlgorithmException If |
| * <code>wrappedKeyAlgorithm</code> is not a valid algorithm |
| * name. |
| */ |
| public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, |
| int wrappedKeyType) |
| throws IllegalStateException, InvalidKeyException, NoSuchAlgorithmException |
| { |
| if (cipherSpi == null) |
| { |
| return null; |
| } |
| if (state != UNWRAP_MODE) |
| { |
| throw new IllegalStateException("instance is not for unwrapping"); |
| } |
| return cipherSpi.engineUnwrap(wrappedKey, wrappedKeyAlgorithm, |
| wrappedKeyType); |
| } |
| |
| /** |
| * Continue a multi-part transformation on an entire byte array, |
| * returning the transformed bytes. |
| * |
| * @param input The input bytes. |
| * @return The transformed bytes. |
| * @throws java.lang.IllegalStateException If this cipher was not |
| * initialized for encryption or decryption. |
| */ |
| public final byte[] update(byte[] input) throws IllegalStateException |
| { |
| return update(input, 0, input.length); |
| } |
| |
| /** |
| * Continue a multi-part transformation on part of a byte array, |
| * returning the transformed bytes. |
| * |
| * @param input The input bytes. |
| * @param inputOffset The index in the input to start. |
| * @param inputLength The number of bytes to transform. |
| * @return The transformed bytes. |
| * @throws java.lang.IllegalStateException If this cipher was not |
| * initialized for encryption or decryption. |
| */ |
| public final byte[] update(byte[] input, int inputOffset, int inputLength) |
| throws IllegalStateException |
| { |
| if (cipherSpi == null) |
| { |
| byte[] b = new byte[inputLength]; |
| System.arraycopy(input, inputOffset, b, 0, inputLength); |
| return b; |
| } |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| { |
| throw new IllegalStateException( |
| "cipher is not for encrypting or decrypting"); |
| } |
| return cipherSpi.engineUpdate(input, inputOffset, inputLength); |
| } |
| |
| /** |
| * Continue a multi-part transformation on part of a byte array, |
| * placing the transformed bytes into the given array. |
| * |
| * @param input The input bytes. |
| * @param inputOffset The index in the input to start. |
| * @param inputLength The number of bytes to transform. |
| * @param output The output byte array. |
| * @return The number of transformed bytes. |
| * @throws java.lang.IllegalStateException If this cipher was not |
| * initialized for encryption or decryption. |
| * @throws javax.security.ShortBufferException If there is not enough |
| * room in the output array to hold the transformed bytes. |
| */ |
| public final int update(byte[] input, int inputOffset, int inputLength, |
| byte[] output) |
| throws IllegalStateException, ShortBufferException |
| { |
| return update(input, inputOffset, inputLength, output, 0); |
| } |
| |
| /** |
| * Continue a multi-part transformation on part of a byte array, |
| * placing the transformed bytes into the given array. |
| * |
| * @param input The input bytes. |
| * @param inputOffset The index in the input to start. |
| * @param inputLength The number of bytes to transform. |
| * @param output The output byte array. |
| * @param outputOffset The index in the output array to start. |
| * @return The number of transformed bytes. |
| * @throws java.lang.IllegalStateException If this cipher was not |
| * initialized for encryption or decryption. |
| * @throws javax.security.ShortBufferException If there is not enough |
| * room in the output array to hold the transformed bytes. |
| */ |
| public final int update(byte[] input, int inputOffset, int inputLength, |
| byte[] output, int outputOffset) |
| throws IllegalStateException, ShortBufferException |
| { |
| if (cipherSpi == null) |
| { |
| if (inputLength > output.length - outputOffset) |
| { |
| throw new ShortBufferException(); |
| } |
| System.arraycopy(input, inputOffset, output, outputOffset, inputLength); |
| return inputLength; |
| } |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| { |
| throw new IllegalStateException( |
| "cipher is not for encrypting or decrypting"); |
| } |
| return cipherSpi.engineUpdate(input, inputOffset, inputLength, |
| output, outputOffset); |
| } |
| |
| /** |
| * Continue a multi-part transformation on a byte buffer, storing |
| * the transformed bytes into another buffer. |
| * |
| * @param input The input buffer. |
| * @param output The output buffer. |
| * @return The number of bytes stored in <i>output</i>. |
| * @throws IllegalArgumentException If the two buffers are the same |
| * object. |
| * @throws IllegalStateException If this cipher was not initialized |
| * for encrypting or decrypting. |
| * @throws ReadOnlyBufferException If the output buffer is not |
| * writable. |
| * @throws ShortBufferException If the output buffer does not have |
| * enough available space for the transformed bytes. |
| * @since 1.5 |
| */ |
| public final int update (ByteBuffer input, ByteBuffer output) |
| throws ReadOnlyBufferException, ShortBufferException |
| { |
| if (input == output) |
| throw new IllegalArgumentException |
| ("input and output buffers must be different"); |
| if (state != ENCRYPT_MODE && state != DECRYPT_MODE) |
| throw new IllegalStateException |
| ("not initialized for encryption or decryption"); |
| return cipherSpi.engineUpdate (input, output); |
| } |
| |
| /** |
| * Wrap a key. |
| * |
| * @param key The key to wrap. |
| * @return The wrapped key. |
| * @throws java.lang.IllegalStateException If this instance was not |
| * initialized for key wrapping. |
| * @throws javax.crypto.IllegalBlockSizeException If this instance has |
| * no padding and the key is not a multiple of the block size. |
| * @throws java.security.InvalidKeyException If this instance cannot |
| * wrap this key. |
| */ |
| public final byte[] wrap(Key key) |
| throws IllegalStateException, IllegalBlockSizeException, InvalidKeyException |
| { |
| if (cipherSpi == null) |
| { |
| return null; |
| } |
| if (state != WRAP_MODE) |
| { |
| throw new IllegalStateException("instance is not for key wrapping"); |
| } |
| return cipherSpi.engineWrap(key); |
| } |
| } |