package javax.crypto; import java.util.StringTokenizer; import java.security.Key; import java.security.Provider; import java.security.SecureRandom; import java.security.AlgorithmParameters; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.InvalidAlgorithmParameterException; import java.security.cert.Certificate; import java.security.spec.AlgorithmParameterSpec; /** * This class provides the functionality of a cryptographic cipher for * encryption and decryption. It forms the core of the Java Cryptographic * Extension (JCE) framework. * <p> * In order to create a Cipher object, the application calls the * Cipher's <code>getInstance</code> method, and passes the name of the * requested <i>transformation</i> to it. Optionally, the name of a provider * may be specified. * <p> * A <i>transformation</i> is a string that describes the operation (or * set of operations) to be performed on the given input, to produce some * output. A transformation always includes the name of a cryptographic * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and * padding scheme. * * <p> A transformation is of the form:<p> * * <ul> * <li>"<i>algorithm/mode/padding</i>" or * <p> * <li>"<i>algorithm</i>" * </ul> * * <P> (in the latter case, * provider-specific default values for the mode and padding scheme are used). * For example, the following is a valid transformation:<p> * * <pre> * Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>"); * </pre> * <p> * When requesting a block cipher in stream cipher mode (e.g., * <code>DES</code> in <code>CFB</code> or <code>OFB</code> mode), the user may * optionally specify the number of bits to be * processed at a time, by appending this number to the mode name as shown in * the "<i>DES/CFB8/NoPadding</i>" and "<i>DES/OFB32/PKCS5Padding</i>" * transformations. If no such number is specified, a provider-specific default * is used. (For example, the "SunJCE" provider uses a default of 64 bits.) */ public class Cipher { static private final int UNINITIALIZED = 0; static public final int ENCRYPT_MODE = 1; static public final int DECRYPT_MODE = 2; static public final int WRAP_MODE = 3; static public final int UNWRAP_MODE = 4; static public final int PUBLIC_KEY = 1; static public final int PRIVATE_KEY = 2; static public final int SECRET_KEY = 3; private CipherSpi cipherSpi; private Provider provider; private String transformation; private int mode = UNINITIALIZED; /** * Creates a Cipher object. * * @param cipherSpi the delegate * @param provider the provider * @param transformation the transformation */ protected Cipher( CipherSpi cipherSpi, Provider provider, String transformation) { this.cipherSpi = cipherSpi; this.provider = provider; this.transformation = transformation; } /** * Generates a <code>Cipher</code> object that implements the specified * transformation. * <p> * If the default provider package supplies an implementation of the * requested transformation, an instance of <code>Cipher</code> containing * that implementation is returned. * If the transformation is not available in the default provider package, * other provider packages are searched. * * @param transformation the name of the transformation, e.g., <i>DES/CBC/PKCS5Padding</i>. * See Appendix A in the Java Cryptography Extension API Specification & Reference * for information about standard transformation names. * * @return a cipher that implements the requested transformation * @exception NoSuchAlgorithmException if the specified transformation is not available in the default * provider package or any of the other provider packages that were searched. * @exception NoSuchPaddingException if <code>transformation</code> contains a padding scheme that is * not available. */ public static final Cipher getInstance( String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException { try { JCEUtil.Implementation imp = JCEUtil.getImplementation("Cipher", transformation, (String) null); if (imp != null) { return new Cipher((CipherSpi)imp.getEngine(), imp.getProvider(), transformation); } // // try the long way // StringTokenizer tok = new StringTokenizer(transformation, "/"); String algorithm = tok.nextToken(); imp = JCEUtil.getImplementation("Cipher", algorithm, (String) null); if (imp == null) { throw new NoSuchAlgorithmException(transformation + " not found"); } CipherSpi cipherSpi = (CipherSpi)imp.getEngine(); // // make sure we don't get fooled by a "//" in the string // if (tok.hasMoreTokens() && !transformation.regionMatches(algorithm.length(), "//", 0, 2)) { cipherSpi.engineSetMode(tok.nextToken()); } if (tok.hasMoreTokens()) { cipherSpi.engineSetPadding(tok.nextToken()); } return new Cipher(cipherSpi, imp.getProvider(), transformation); } catch (NoSuchProviderException e) { throw new NoSuchAlgorithmException(transformation + " not found"); } } /** * Creates a <code>Cipher</code> object that implements the specified * transformation, as supplied by the specified provider. * * @param transformation the name of the transformation, e.g., <i>DES/CBC/PKCS5Padding</i>. * See Appendix A in the Java Cryptography Extension API Specification & Reference * for information about standard transformation names. * * @param provider the provider * @return a cipher that implements the requested transformation * @exception NoSuchAlgorithmException if no transformation was specified, or if the specified * transformation is not available from the specified provider. * @exception NoSuchPaddingException if <code>transformation</code> contains a padding scheme * that is not available. */ public static final Cipher getInstance( String transformation, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException { if (transformation == null) { throw new IllegalArgumentException("No transformation specified for Cipher.getInstance()"); } JCEUtil.Implementation imp = JCEUtil.getImplementation("Cipher", transformation, provider); if (imp != null) { return new Cipher((CipherSpi)imp.getEngine(), imp.getProvider(), transformation); } // // try the long way // StringTokenizer tok = new StringTokenizer(transformation, "/"); String algorithm = tok.nextToken(); imp = JCEUtil.getImplementation("Cipher", algorithm, provider); if (imp == null) { throw new NoSuchAlgorithmException(transformation + " not found"); } CipherSpi cipherSpi = (CipherSpi)imp.getEngine(); // // make sure we don't get fooled by a "//" in the string // if (tok.hasMoreTokens() && !transformation.regionMatches(algorithm.length(), "//", 0, 2)) { cipherSpi.engineSetMode(tok.nextToken()); } if (tok.hasMoreTokens()) { cipherSpi.engineSetPadding(tok.nextToken()); } return new Cipher(cipherSpi, imp.getProvider(), transformation); } /** * Creates a <code>Cipher</code> object that implements the specified * transformation, as supplied by the specified provider. * * @param transformation the name of the transformation, e.g., <i>DES/CBC/PKCS5Padding</i>. * See Appendix A in the Java Cryptography Extension API Specification & Reference * for information about standard transformation names. * * @param provider the name of the provider * @return a cipher that implements the requested transformation * @exception NoSuchAlgorithmException if no transformation was specified, or if the specified * transformation is not available from the specified provider. * @exception NoSuchProviderException if the specified provider has not been configured. * @exception NoSuchPaddingException if <code>transformation</code> contains a padding scheme * that is not available. */ public static final Cipher getInstance( String transformation, String provider) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { if (transformation == null) { throw new IllegalArgumentException("No transformation specified for Cipher.getInstance()"); } JCEUtil.Implementation imp = JCEUtil.getImplementation("Cipher", transformation, provider); if (imp != null) { return new Cipher((CipherSpi)imp.getEngine(), imp.getProvider(), transformation); } // // try the long way // StringTokenizer tok = new StringTokenizer(transformation, "/"); String algorithm = tok.nextToken(); imp = JCEUtil.getImplementation("Cipher", algorithm, provider); if (imp == null) { throw new NoSuchAlgorithmException(transformation + " not found"); } CipherSpi cipherSpi = (CipherSpi)imp.getEngine(); // // make sure we don't get fooled by a "//" in the string // if (tok.hasMoreTokens() && !transformation.regionMatches(algorithm.length(), "//", 0, 2)) { cipherSpi.engineSetMode(tok.nextToken()); } if (tok.hasMoreTokens()) { cipherSpi.engineSetPadding(tok.nextToken()); } return new Cipher(cipherSpi, imp.getProvider(), transformation); } /** * Returns the provider of this <code>Cipher</code> object. * * @return the provider of this <code>Cipher</code> object */ public final Provider getProvider() { return provider; } /** * Returns the algorithm name of this <code>Cipher</code> object. * <p> * This is the same name that was specified in one of the * <code>getInstance</code> calls that created this <code>Cipher</code> * object.. * * @return the algorithm name of this <code>Cipher</code> object. */ public final String getAlgorithm() { return transformation; } /** * Returns the block size (in bytes). * * @return the block size (in bytes), or 0 if the underlying algorithm is not a block cipher */ public final int getBlockSize() { return cipherSpi.engineGetBlockSize(); } /** * Returns the length in bytes that an output buffer would need to be in * order to hold the result of the next <code>update</code> or * <code>doFinal</code> operation, given the input length <code>inputLen</code> (in bytes). * <p> * This call takes into account any unprocessed (buffered) data from a * previous <code>update</code> call, and padding. * <p> * The actual output length of the next <code>update</code> or * <code>doFinal</code> call may be smaller than the length returned by * this method. * * @param inputLen the input length (in bytes) * @return the required output buffer size (in bytes) * @exception java.lang.IllegalStateException if this cipher is in a wrong state (e.g., has not * yet been initialized) */ public final int getOutputSize( int inputLen) throws IllegalStateException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } return cipherSpi.engineGetOutputSize(inputLen); } /** * Returns the initialization vector (IV) in a new buffer. * <p> * This is useful in the case where a random IV was created, * or in the context of password-based encryption or decryption, where the IV * is derived from a user-supplied password. * * @return the initialization vector in a new buffer, or null if the * underlying algorithm does not use an IV, or if the IV has not yet been set. */ public final byte[] getIV() { return cipherSpi.engineGetIV(); } /** * Returns the parameters used with this cipher. * <p> * The returned parameters may be the same that were used to initialize * this cipher, or may contain a combination of default and random * parameter values used by the underlying cipher implementation if this * cipher requires algorithm parameters but was not initialized with any. * * @return the parameters used with this cipher, or null if this cipher * does not use any parameters. */ public final AlgorithmParameters getParameters() { return cipherSpi.engineGetParameters(); } /** * Returns the exemption mechanism object used with this cipher. * * @return the exemption mechanism object used with this cipher, or * null if this cipher does not use any exemption mechanism. */ public final ExemptionMechanism getExemptionMechanism() { return null; } /** * Initializes this cipher with a key. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If this cipher requires any algorithm parameters that cannot be * derived from the given <code>key</code>, the underlying cipher * implementation is supposed to generate the required parameters itself * (using provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidKeyException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#getParameters()">getParameters</a> or * <a href = "#getIV()">getIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them using the <a href="http://java.sun.com/products/jdk/1.2/docs/api/java.security.SecureRandom.html"> * <code>SecureRandom</code></a> implementation of the highest-priority * installed provider as the source of randomness. * (If none of the installed providers supply an implementation of * SecureRandom, a system-provided source of randomness will be used.) * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * * @param opmode the operation mode of this cipher (this is one of the following: * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) * @param key the key * @exception InvalidKeyException if the given key is inappropriate for * initializing this cipher, or if this cipher is being initialized for * decryption and requires algorithm parameters that cannot be * determined from the given key, or if the given key has a keysize that * exceeds the maximum allowable keysize (as determined from the * configured jurisdiction policy files). Note: Jurisdiction files are ignored * in this implementation. */ public final void init( int opmode, Key key) throws InvalidKeyException { cipherSpi.engineInit(opmode, key, new SecureRandom()); mode = opmode; } /** * Initializes this cipher with a key and a source of randomness. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If this cipher requires any algorithm parameters that cannot be * derived from the given <code>key</code>, the underlying cipher * implementation is supposed to generate the required parameters itself * (using provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidKeyException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#engineGetParameters()">engineGetParameters</a> or * <a href = "#engineGetIV()">engineGetIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them from <code>random</code>. * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * @param opmode the operation mode of this cipher (this is one of the * following: <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) * @param key the encryption key * @param random the source of randomness * @exception InvalidKeyException if the given key is inappropriate for * initializing this cipher, or if this cipher is being initialized for * decryption and requires algorithm parameters that cannot be * determined from the given key, or if the given key has a keysize that * exceeds the maximum allowable keysize (as determined from the * configured jurisdiction policy files). Note: Jurisdiction files are ignored * in this implementation. */ public final void init( int opmode, Key key, SecureRandom random) throws InvalidKeyException { cipherSpi.engineInit(opmode, key, random); mode = opmode; } /** * Initializes this cipher with a key and a set of algorithm parameters. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If this cipher requires any algorithm parameters and * <code>params</code> is null, the underlying cipher implementation is * supposed to generate the required parameters itself (using * provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidAlgorithmParameterException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#getParameters()">getParameters</a> or * <a href = "#getIV()">getIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them using the * <a href="http://java.sun.com/products/jdk/1.2/docs/api/java.security.SecureRandom.html"> * <code>SecureRandom</code></a> implementation of the highest-priority * installed provider as the source of randomness. * (If none of the installed providers supply an implementation of * SecureRandom, a system-provided source of randomness will be used.) * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * * @param opmode the operation mode of this cipher (this is one of the * following: <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code> * or <code>UNWRAP_MODE</code>) * @param key the encryption key * @param params the algorithm parameters * @exception InvalidKeyException if the given key is inappropriate for initializing this * cipher, or its keysize exceeds the maximum allowable keysize (as determined from the * configured jurisdiction policy files). * @exception InvalidAlgorithmParameterException if the given algorithm parameters are * inappropriate for this cipher, or this cipher is being initialized for decryption and * requires algorithm parameters and <code>params</code> is null, or the given algorithm * parameters imply a cryptographic strength that would exceed the legal limits (as determined * from the configured jurisdiction policy files). Note: Jurisdiction files are ignored * in this implementation. */ public final void init( int opmode, Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { cipherSpi.engineInit(opmode, key, params, new SecureRandom()); mode = opmode; } /** * Initializes this cipher with a key, a set of algorithm * parameters, and a source of randomness. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If this cipher requires any algorithm parameters and * <code>params</code> is null, the underlying cipher implementation is * supposed to generate the required parameters itself (using * provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidAlgorithmParameterException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#getParameters()">getParameters</a> or * <a href = "#getIV()">getIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them from <code>random</code>. * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * * @param opmode the operation mode of this cipher (this is one of the * following: <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) * @param key the encryption key * @param params the algorithm parameters * @param random the source of randomness * @exception InvalidKeyException if the given key is inappropriate for * initializing this cipher, or its keysize exceeds the maximum allowable * keysize (as determined from the configured jurisdiction policy files). * @exception InvalidAlgorithmParameterException if the given algorithm * parameters are inappropriate for this cipher, * or this cipher is being initialized for decryption and requires * algorithm parameters and <code>params</code> is null, or the given * algorithm parameters imply a cryptographic strength that would exceed * the legal limits (as determined from the configured jurisdiction * policy files). * Note: Jurisdiction files are ignored in this implementation. */ public final void init( int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { cipherSpi.engineInit(opmode, key, params, random); mode = opmode; } /** * Initializes this cipher with a key and a set of algorithm * parameters. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If this cipher requires any algorithm parameters and * <code>params</code> is null, the underlying cipher implementation is * supposed to generate the required parameters itself (using * provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidAlgorithmParameterException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#getParameters()">getParameters</a> or * <a href = "#getIV()">getIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them using the * <a href="http://java.sun.com/products/jdk/1.2/docs/api/java.security.SecureRandom.html"> * <code>SecureRandom</code></a> implementation of the highest-priority * installed provider as the source of randomness. * (If none of the installed providers supply an implementation of * SecureRandom, a system-provided source of randomness will be used.) * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * * @param opmode the operation mode of this cipher (this is one of the * following: <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code> * or <code>UNWRAP_MODE</code>) * @param key the encryption key * @param params the algorithm parameters * @exception InvalidKeyException if the given key is inappropriate for * initializing this cipher, or its keysize exceeds the maximum allowable * keysize (as determined from the configured jurisdiction policy files). * @exception InvalidAlgorithmParameterException if the given algorithm * parameters are inappropriate for this cipher, * or this cipher is being initialized for decryption and requires * algorithm parameters and <code>params</code> is null, or the given * algorithm parameters imply a cryptographic strength that would exceed * the legal limits (as determined from the configured jurisdiction * policy files). * Note: Jurisdiction files are ignored in this implementation. */ public final void init( int opmode, Key key, AlgorithmParameters params) throws InvalidKeyException, InvalidAlgorithmParameterException { cipherSpi.engineInit(opmode, key, params, new SecureRandom()); mode = opmode; } /** * Initializes this cipher with a key, a set of algorithm * parameters, and a source of randomness. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If this cipher requires any algorithm parameters and * <code>params</code> is null, the underlying cipher implementation is * supposed to generate the required parameters itself (using * provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidAlgorithmParameterException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#getParameters()">getParameters</a> or * <a href = "#getIV()">getIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them from <code>random</code>. * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * * @param opmode the operation mode of this cipher (this is one of the * following: <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, <code>WRAP_MODE</code> * or <code>UNWRAP_MODE</code>) * @param key the encryption key * @param params the algorithm parameters * @param random the source of randomness * @exception InvalidKeyException if the given key is inappropriate for * initializing this cipher, or its keysize exceeds the maximum allowable * keysize (as determined from the configured jurisdiction policy files). * @exception InvalidAlgorithmParameterException if the given algorithm * parameters are inappropriate for this cipher, * or this cipher is being initialized for decryption and requires * algorithm parameters and <code>params</code> is null, or the given * algorithm parameters imply a cryptographic strength that would exceed * the legal limits (as determined from the configured jurisdiction * policy files). * Note: Jurisdiction files are ignored in this implementation. */ public final void init( int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { cipherSpi.engineInit(opmode, key, params, random); mode = opmode; } /** * Initializes this cipher with the public key from the given certificate. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending * on the value of <code>opmode</code>. * <p> * If the certificate is of type X.509 and has a <i>key usage</i> * extension field marked as critical, and the value of the <i>key usage</i> * extension field implies that the public key in * the certificate and its corresponding private key are not * supposed to be used for the operation represented by the value * of <code>opmode</code>, * an <code>InvalidKeyException</code> * is thrown. * <p> * If this cipher requires any algorithm parameters that cannot be * derived from the public key in the given certificate, the underlying * cipher * implementation is supposed to generate the required parameters itself * (using provider-specific default or ramdom values) if it is being * initialized for encryption or key wrapping, and raise an <code> * InvalidKeyException</code> if it is being initialized for decryption or * key unwrapping. * The generated parameters can be retrieved using * <a href = "#getParameters()">getParameters</a> or * <a href = "#getIV()">getIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them using the * <a href="http://java.sun.com/products/jdk/1.2/docs/api/java.security.SecureRandom.html"> * <code>SecureRandom</code></a> * implementation of the highest-priority installed provider as the source of randomness. * (If none of the installed providers supply an implementation of * SecureRandom, a system-provided source of randomness will be used.) * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * @param opmode the operation mode of this cipher (this is one of the * following: * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) * @param certificate the certificate * @exception InvalidKeyException if the public key in the given * certificate is inappropriate for initializing this cipher, or this * cipher is being initialized for decryption or unwrapping keys and * requires algorithm parameters that cannot be determined from the * public key in the given certificate, or the keysize of the public key * in the given certificate has a keysize that exceeds the maximum * allowable keysize (as determined by the configured jurisdiction policy * files). * Note: Jurisdiction files are ignored in this implementation. */ public final void init( int opmode, Certificate certificate) throws InvalidKeyException { cipherSpi.engineInit(opmode, certificate.getPublicKey(), new SecureRandom()); mode = opmode; } /** * Initializes this cipher with the public key from the given certificate * and a source of randomness. * <p>The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping * or key unwrapping, depending on * the value of <code>opmode</code>. * <p> * If the certificate is of type X.509 and has a <i>key usage</i> * extension field marked as critical, and the value of the <i>key usage</i> * extension field implies that the public key in * the certificate and its corresponding private key are not * supposed to be used for the operation represented by the value of * <code>opmode</code>, * an <code>InvalidKeyException</code> * is thrown. * <p> * If this cipher requires any algorithm parameters that cannot be * derived from the public key in the given <code>certificate</code>, * the underlying cipher * implementation is supposed to generate the required parameters itself * (using provider-specific default or random values) if it is being * initialized for encryption or key wrapping, and raise an * <code>InvalidKeyException</code> if it is being * initialized for decryption or key unwrapping. * The generated parameters can be retrieved using * <a href = "#engineGetParameters()">engineGetParameters</a> or * <a href = "#engineGetIV()">engineGetIV</a> (if the parameter is an IV). * <p> * If this cipher (including its underlying feedback or padding scheme) * requires any random bytes (e.g., for parameter generation), it will get * them from <code>random</code>. * <p> * Note that when a Cipher object is initialized, it loses all * previously-acquired state. In other words, initializing a Cipher is * equivalent to creating a new instance of that Cipher and initializing * it. * * @param opmode the operation mode of this cipher (this is one of the * following: <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) * @param certificate the certificate * @param random the source of randomness * @exception InvalidKeyException if the public key in the given * certificate is inappropriate for initializing this cipher, or this * cipher is being initialized for decryption or unwrapping keys and * requires algorithm parameters that cannot be determined from the * public key in the given certificate, or the keysize of the public key * in the given certificate has a keysize that exceeds the maximum * allowable keysize (as determined by the configured jurisdiction policy * files). */ public final void init( int opmode, Certificate certificate, SecureRandom random) throws InvalidKeyException { cipherSpi.engineInit(opmode, certificate.getPublicKey(), random); mode = opmode; } /** * Continues a multiple-part encryption or decryption operation * (depending on how this cipher was initialized), processing another data * part. * <p> * The bytes in the <code>input</code> buffer are processed, and the * result is stored in a new buffer. * <p> * If <code>input</code> has a length of zero, this method returns * <code>null</code>. * * @param input the input buffer * @return the new buffer with the result, or null if the underlying * cipher is a block cipher and the input data is too short to result in a * new block. * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) */ public final byte[] update( byte[] input) throws IllegalStateException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input buffer"); } if (input.length == 0) { return null; } return cipherSpi.engineUpdate(input, 0, input.length); } /** * Continues a multiple-part encryption or decryption operation * (depending on how this cipher was initialized), processing another data * part. * <p> * The first <code>inputLen</code> bytes in the <code>input</code> * buffer, starting at <code>inputOffset</code> inclusive, are processed, * and the result is stored in a new buffer. * <p> * If <code>inputLen</code> is zero, this method returns * <code>null</code>. * * @param input the input buffer * @param inputOffset the offset in <code>input</code> where the input * starts * @param inputLen the input length * @return the new buffer with the result, or null if the underlying * cipher is a block cipher and the input data is too short to result in a * new block. * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) */ public final byte[] update( byte[] input, int inputOffset, int inputLen) throws IllegalStateException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (inputLen < 0 || inputOffset < 0 || inputLen > (input.length - inputOffset)) { throw new IllegalArgumentException("Bad inputOffset/inputLen"); } if (inputLen == 0) { return null; } return cipherSpi.engineUpdate(input, inputOffset, inputLen); } /** * Continues a multiple-part encryption or decryption operation * (depending on how this cipher was initialized), processing another data * part. * <p> * The first <code>inputLen</code> bytes in the <code>input</code> * buffer, starting at <code>inputOffset</code> inclusive, are processed, * and the result is stored in the <code>output</code> buffer. * <p> * If the <code>output</code> buffer is too small to hold the result, * a <code>ShortBufferException</code> is thrown. In this case, repeat this * call with a larger output buffer. Use * <a href = "#getOutputSize(int)">getOutputSize</a> to determine how big * the output buffer should be. * <p> * If <code>inputLen</code> is zero, this method returns * a length of zero. * * @param input the input buffer * @param inputOffset the offset in <code>input</code> where the input starts * @param inputLen the input length * @param output the buffer for the result * @return the number of bytes stored in <code>output</code> * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception ShortBufferException if the given output buffer is too small * to hold the result */ public final int update( byte[] input, int inputOffset, int inputLen, byte[] output) throws IllegalStateException, ShortBufferException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (inputLen < 0 || inputOffset < 0 || inputLen > (input.length - inputOffset)) { throw new IllegalArgumentException("Bad inputOffset/inputLen"); } if (output == null) { throw new IllegalArgumentException("Null output passed"); } if (inputLen == 0) { return 0; } return cipherSpi.engineUpdate(input, inputOffset, inputLen, output, 0); } /** * Continues a multiple-part encryption or decryption operation * (depending on how this cipher was initialized), processing another data * part. * <p> * The first <code>inputLen</code> bytes in the <code>input</code> * buffer, starting at <code>inputOffset</code> inclusive, are processed, * and the result is stored in the <code>output</code> buffer, starting at * <code>outputOffset</code> inclusive. * <p> * If the <code>output</code> buffer is too small to hold the result, * a <code>ShortBufferException</code> is thrown. In this case, repeat this * call with a larger output buffer. Use * <a href = "#getOutputSize(int)">getOutputSize</a> to determine how big * the output buffer should be. * <p> * If <code>inputLen</code> is zero, this method returns * a length of zero. * * @param input the input buffer * @param inputOffset the offset in <code>input</code> where the input starts * @param inputLen the input length * @param output the buffer for the result * @param outputOffset the offset in <code>output</code> where the result * is stored * @return the number of bytes stored in <code>output</code> * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception ShortBufferException if the given output buffer is too small * to hold the result */ public final int update( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws IllegalStateException, ShortBufferException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (inputLen < 0 || inputOffset < 0 || inputLen > (input.length - inputOffset)) { throw new IllegalArgumentException("Bad inputOffset/inputLen"); } if (output == null) { throw new IllegalArgumentException("Null output passed"); } if (outputOffset < 0 || outputOffset >= output.length) { throw new IllegalArgumentException("Bad outputOffset"); } if (inputLen == 0) { return 0; } return cipherSpi.engineUpdate(input, inputOffset, inputLen, output, outputOffset); } /** * Finishes a multiple-part encryption or decryption operation, depending * on how this cipher was initialized. * <p> * Input data that may have been buffered during a previous * <code>update</code> operation is processed, with padding (if requested) * being applied. * The result is stored in a new buffer. * <p> * A call to this method resets this cipher object to the state * it was in when previously initialized via a call to <code>init</code>. * That is, the object is reset and available to encrypt or decrypt * (depending on the operation mode that was specified in the call to * <code>init</code>) more data. * @return the new buffer with the result * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception IllegalBlockSizeException if this cipher is a block cipher, * no padding has been requested (only in encryption mode), and the total * input length of the data processed by this cipher is not a multiple of * block size * @exception BadPaddingException if this cipher is in decryption mode, * and (un)padding has been requested, but the decrypted data is not * bounded by the appropriate padding bytes */ public final byte[] doFinal() throws java.lang.IllegalStateException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } return cipherSpi.engineDoFinal(null, 0, 0); } /** * Finishes a multiple-part encryption or decryption operation, depending * on how this cipher was initialized. * <p> * Input data that may have been buffered during a previous * <code>update</code> operation is processed, with padding (if requested) * being applied. * The result is stored in the <code>output</code> buffer, starting at * <code>outputOffset</code> inclusive. * <p> * If the <code>output</code> buffer is too small to hold the result, * a <code>ShortBufferException</code> is thrown. In this case, repeat this * call with a larger output buffer. Use * <a href = "#getOutputSize(int)">getOutputSize</a> to determine how big * the output buffer should be. * <p> * A call to this method resets this cipher object to the state * it was in when previously initialized via a call to <code>init</code>. * That is, the object is reset and available to encrypt or decrypt * (depending on the operation mode that was specified in the call to * <code>init</code>) more data. * * @param output the buffer for the result * @param outputOffset the offset in <code>output</code> where the result * is stored * @return the number of bytes stored in <code>output</code> * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception IllegalBlockSizeException if this cipher is a block cipher, * no padding has been requested (only in encryption mode), and the total * input length of the data processed by this cipher is not a multiple of * block size * @exception ShortBufferException if the given output buffer is too small * to hold the result * @exception BadPaddingException if this cipher is in decryption mode, * and (un)padding has been requested, but the decrypted data is not * bounded by the appropriate padding bytes */ public final int doFinal( byte[] output, int outputOffset) throws IllegalStateException, IllegalBlockSizeException, ShortBufferException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (output == null) { throw new IllegalArgumentException("Null output passed"); } if (outputOffset < 0 || outputOffset >= output.length) { throw new IllegalArgumentException("Bad outputOffset"); } return cipherSpi.engineDoFinal(null, 0, 0, output, outputOffset); } /** * Encrypts or decrypts data in a single-part operation, or finishes a * multiple-part operation. The data is encrypted or decrypted, * depending on how this cipher was initialized. * <p> * The bytes in the <code>input</code> buffer, and any input bytes that * may have been buffered during a previous <code>update</code> operation, * are processed, with padding (if requested) being applied. * The result is stored in a new buffer. * <p> * A call to this method resets this cipher object to the state * it was in when previously initialized via a call to <code>init</code>. * That is, the object is reset and available to encrypt or decrypt * (depending on the operation mode that was specified in the call to * <code>init</code>) more data. * * @param input the input buffer * @return the new buffer with the result * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception IllegalBlockSizeException if this cipher is a block cipher, * no padding has been requested (only in encryption mode), and the total * input length of the data processed by this cipher is not a multiple of * block size * @exception BadPaddingException if this cipher is in decryption mode, * and (un)padding has been requested, but the decrypted data is not * bounded by the appropriate padding bytes */ public final byte[] doFinal( byte[] input) throws java.lang.IllegalStateException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } return cipherSpi.engineDoFinal(input, 0, input.length); } /** * Encrypts or decrypts data in a single-part operation, or finishes a * multiple-part operation. The data is encrypted or decrypted, * depending on how this cipher was initialized. * <p> * The first <code>inputLen</code> bytes in the <code>input</code> * buffer, starting at <code>inputOffset</code> inclusive, and any input * bytes that may have been buffered during a previous <code>update</code> * operation, are processed, with padding (if requested) being applied. * The result is stored in a new buffer. * <p>A call to this method resets this cipher object to the state * it was in when previously initialized via a call to <code>init</code>. * That is, the object is reset and available to encrypt or decrypt * (depending on the operation mode that was specified in the call to * <code>init</code>) more data. * * @param input the input buffer * @param inputOffset the offset in <code>input</code> where the input starts * @param inputLen the input length * @return the new buffer with the result * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception IllegalBlockSizeException if this cipher is a block cipher, * no padding has been requested (only in encryption mode), and the total * input length of the data processed by this cipher is not a multiple of * block size * @exception BadPaddingException if this cipher is in decryption mode, * and (un)padding has been requested, but the decrypted data is not * bounded by the appropriate padding bytes */ public final byte[] doFinal( byte[] input, int inputOffset, int inputLen) throws IllegalStateException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (inputLen < 0 || inputOffset < 0 || inputLen > (input.length - inputOffset)) { throw new IllegalArgumentException("Bad inputOffset/inputLen"); } return cipherSpi.engineDoFinal(input, inputOffset, inputLen); } /** * Encrypts or decrypts data in a single-part operation, or finishes a * multiple-part operation. The data is encrypted or decrypted, * depending on how this cipher was initialized. * <p> * The first <code>inputLen</code> bytes in the <code>input</code> * buffer, starting at <code>inputOffset</code> inclusive, and any input * bytes that may have been buffered during a previous <code>update</code> * operation, are processed, with padding (if requested) being applied. * The result is stored in the <code>output</code> buffer. * <p> * If the <code>output</code> buffer is too small to hold the result, * a <code>ShortBufferException</code> is thrown. In this case, repeat this * call with a larger output buffer. Use * <a href = "#getOutputSize(int)">getOutputSize</a> to determine how big * the output buffer should be. * <p> * A call to this method resets this cipher object to the state * it was in when previously initialized via a call to <code>init</code>. * That is, the object is reset and available to encrypt or decrypt * (depending on the operation mode that was specified in the call to * <code>init</code>) more data. * @param input the input buffer * @param inputOffset the offset in <code>input</code> where the input starts * @param inputLen the input length * @param output the buffer for the result * @return the number of bytes stored in <code>output</code> * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception IllegalBlockSizeException if this cipher is a block cipher, * no padding has been requested (only in encryption mode), and the total * input length of the data processed by this cipher is not a multiple of * block size * @exception ShortBufferException if the given output buffer is too small * to hold the result * @exception BadPaddingException if this cipher is in decryption mode, * and (un)padding has been requested, but the decrypted data is not * bounded by the appropriate padding bytes */ public final int doFinal( byte[] input, int inputOffset, int inputLen, byte[] output) throws IllegalStateException, ShortBufferException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (inputLen < 0 || inputOffset < 0 || inputLen > (input.length - inputOffset)) { throw new IllegalArgumentException("Bad inputOffset/inputLen"); } if (output == null) { throw new IllegalArgumentException("Null output passed"); } return cipherSpi.engineDoFinal(input, inputOffset, inputLen, output, 0); } /** * Encrypts or decrypts data in a single-part operation, or finishes a * multiple-part operation. The data is encrypted or decrypted, * depending on how this cipher was initialized. * <p> * The first <code>inputLen</code> bytes in the <code>input</code> * buffer, starting at <code>inputOffset</code> inclusive, and any input * bytes that may have been buffered during a previous * <code>update</code> operation, are processed, with padding * (if requested) being applied. * The result is stored in the <code>output</code> buffer, starting at * <code>outputOffset</code> inclusive. * <p> * If the <code>output</code> buffer is too small to hold the result, * a <code>ShortBufferException</code> is thrown. In this case, repeat this * call with a larger output buffer. Use * <a href = "#getOutputSize(int)">getOutputSize</a> to determine how big * the output buffer should be. * <p> * A call to this method resets this cipher object to the state * it was in when previously initialized via a call to <code>init</code>. * That is, the object is reset and available to encrypt or decrypt * (depending on the operation mode that was specified in the call to * <code>init</code>) more data. * * @param input the input buffer * @param inputOffset the offset in <code>input</code> where the input starts * @param inputLen the input length * @param output the buffer for the result * @param outputOffset the offset in <code>output</code> where the result is * stored * @return the number of bytes stored in <code>output</code> * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized) * @exception IllegalBlockSizeException if this cipher is a block cipher, * no padding has been requested (only in encryption mode), and the total * input length of the data processed by this cipher is not a multiple of * block size * @exception ShortBufferException if the given output buffer is too small * to hold the result * @exception BadPaddingException if this cipher is in decryption mode, * and (un)padding has been requested, but the decrypted data is not * bounded by the appropriate padding bytes */ public final int doFinal( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws IllegalStateException, ShortBufferException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException("Cipher is uninitialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (inputLen < 0 || inputOffset < 0 || inputLen > (input.length - inputOffset)) { throw new IllegalArgumentException("Bad inputOffset/inputLen"); } if (output == null) { throw new IllegalArgumentException("Null output passed"); } if (outputOffset < 0 || outputOffset >= output.length) { throw new IllegalArgumentException("Bad outputOffset"); } return cipherSpi.engineDoFinal(input, inputOffset, inputLen, output, outputOffset); } /** * Wrap a key. * * @param key the key to be wrapped. * @return the wrapped key. * @exception IllegalStateException if this cipher is in a wrong state (e.g., has not * been initialized). * @exception IllegalBlockSizeException if this cipher is a block cipher, no padding * has been requested, and the length of the encoding of the key to be wrapped is not a * multiple of the block size. * @exception <DD>java.security.InvalidKeyException - if it is impossible or unsafe to * wrap the key with this cipher (e.g., a hardware protected key is being passed to a * software-only cipher). */ public final byte[] wrap( Key key) throws IllegalStateException, IllegalBlockSizeException, InvalidKeyException { if (mode != WRAP_MODE) { throw new IllegalStateException("Cipher is not initialised for wrapping"); } if (key == null) { throw new IllegalArgumentException("Null key passed"); } return cipherSpi.engineWrap(key); } /** * Unwrap a previously wrapped key. * * @param wrappedKey the key to be unwrapped. * @param wrappedKeyAlgorithm the algorithm associated with the wrapped key. * @param wrappedKeyType the type of the wrapped key. This must be one of * <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or <code>PUBLIC_KEY</code>. * @return the unwrapped key. * @exception IllegalStateException if this cipher is in a wrong state * (e.g., has not been initialized). * @exception InvalidKeyException if <code>wrappedKey</code> does not * represent a wrapped key, or if the algorithm associated with the * wrapped key is different from <code>wrappedKeyAlgorithm</code> * and/or its key type is different from <code>wrappedKeyType</code>. * @exception NoSuchAlgorithmException - if no installed providers * can create keys for the <code>wrappedKeyAlgorithm</code>. */ public final Key unwrap( byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType) throws IllegalStateException, InvalidKeyException, NoSuchAlgorithmException { if (mode != UNWRAP_MODE) { throw new IllegalStateException("Cipher is not initialised for unwrapping"); } if (wrappedKeyType != SECRET_KEY && wrappedKeyType != PUBLIC_KEY && wrappedKeyType != PRIVATE_KEY) { throw new IllegalArgumentException("Invalid key type argument"); } if (wrappedKey == null) { throw new IllegalArgumentException("Null wrappedKey passed"); } if (wrappedKeyAlgorithm == null) { throw new IllegalArgumentException("Null wrappedKeyAlgorithm string passed"); } return cipherSpi.engineUnwrap(wrappedKey, wrappedKeyAlgorithm, wrappedKeyType); } }