diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-01-27 14:00:22 +0100 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-01-27 14:00:22 +0100 |
commit | 5aec25ac0501352e4cb6645c86869dde6e91f0d0 (patch) | |
tree | ee9adfd55cddf25f098e5e028d585a72de7cd70c /libraries/spongycastle/jce/src/main/java/javax/crypto | |
parent | 8ca42b9bf953c6195ee0c17ef48a3154c126cc04 (diff) | |
download | open-keychain-5aec25ac0501352e4cb6645c86869dde6e91f0d0.tar.gz open-keychain-5aec25ac0501352e4cb6645c86869dde6e91f0d0.tar.bz2 open-keychain-5aec25ac0501352e4cb6645c86869dde6e91f0d0.zip |
Add spongy castle sources to libraries folder
Diffstat (limited to 'libraries/spongycastle/jce/src/main/java/javax/crypto')
41 files changed, 7422 insertions, 0 deletions
diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/BadPaddingException.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/BadPaddingException.java new file mode 100644 index 000000000..d1df0d0b2 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/BadPaddingException.java @@ -0,0 +1,37 @@ +package javax.crypto; + +import java.security.GeneralSecurityException; + +/** + * This exception is thrown when a particular padding mechanism is + * expected for the input data but the data is not padded properly + * + */ +public class BadPaddingException + extends GeneralSecurityException +{ + private static final long serialVersionUID = -5315033893984728443L; + + /** + * Constructs a BadPaddingException with no detail + * message. A detail message is a String that describes this + * particular exception. + */ + public BadPaddingException() + { + } + + /** + * Constructs a BadPaddingException with the specified + * detail message. A detail message is a String that describes + * this particular exception, which may, for example, specify which + * algorithm is not available. + * + * @param msg the detail message. + */ + public BadPaddingException( + String msg) + { + super(msg); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/Cipher.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/Cipher.java new file mode 100644 index 000000000..bf9fd3743 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/Cipher.java @@ -0,0 +1,1509 @@ +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); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherInputStream.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherInputStream.java new file mode 100644 index 000000000..9e41fb906 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherInputStream.java @@ -0,0 +1,349 @@ +package javax.crypto; + +import java.io.InputStream; +import java.io.IOException; +import java.io.FilterInputStream; + +/** + * A CipherInputStream is composed of an InputStream and a Cipher so + * that read() methods return data that are read in from the + * underlying InputStream but have been additionally processed by the + * Cipher. The Cipher must be fully initialized before being used by + * a CipherInputStream. + * <p> + * For example, if the Cipher is initialized for decryption, the + * CipherInputStream will attempt to read in data and decrypt them, + * before returning the decrypted data. + * <p> + * This class adheres strictly to the semantics, especially the + * failure semantics, of its ancestor classes + * java.io.FilterInputStream and java.io.InputStream. This class has + * exactly those methods specified in its ancestor classes, and + * overrides them all. Moreover, this class catches all exceptions + * that are not thrown by its ancestor classes. In particular, the + * <code>skip</code> method skips, and the <code>available</code> + * method counts only data that have been processed by the encapsulated Cipher. + * <p> + * It is crucial for a programmer using this class not to use + * methods that are not defined or overriden in this class (such as a + * new method or constructor that is later added to one of the super + * classes), because the design and implementation of those methods + * are unlikely to have considered security impact with regard to + * CipherInputStream. + * + * @since JCE1.2 + * @see InputStream + * @see FilterInputStream + * @see Cipher + * @see CipherOutputStream + */ +public class CipherInputStream + extends FilterInputStream +{ + private Cipher c; + + private byte[] buf; + private byte[] inBuf; + + private int bufOff; + private int maxBuf; + private boolean finalized; + + private static final int INPUT_BUF_SIZE = 2048; + + /** + * Constructs a CipherInputStream from an InputStream and a + * Cipher. + */ + public CipherInputStream( + InputStream is, + Cipher c) + { + super(is); + + this.c = c; + + buf = new byte[c.getOutputSize(INPUT_BUF_SIZE)]; + inBuf = new byte[INPUT_BUF_SIZE]; + } + + /** + * Constructs a CipherInputStream from an InputStream without + * specifying a Cipher. This has the effect of constructing a + * CipherInputStream using a NullCipher. + */ + protected CipherInputStream( + InputStream is) + { + this(is, new NullCipher()); + } + + /** + * grab the next chunk of input from the underlying input stream + */ + private int nextChunk() + throws IOException + { + int available = super.available(); + + // must always try to read 1 byte! + // some buggy InputStreams return < 0! + if (available <= 0) + { + available = 1; + } + + if (available > inBuf.length) + { + available = super.read(inBuf, 0, inBuf.length); + } + else + { + available = super.read(inBuf, 0, available); + } + + if (available < 0) + { + if (finalized) + { + return -1; + } + + try + { + buf = c.doFinal(); + } + catch (Exception e) + { + throw new IOException("error processing stream: " + e.toString()); + } + + bufOff = 0; + + if (buf != null) + { + maxBuf = buf.length; + } + else + { + maxBuf = 0; + } + + finalized = true; + + if (bufOff == maxBuf) + { + return -1; + } + } + else + { + bufOff = 0; + + try + { + maxBuf = c.update(inBuf, 0, available, buf, 0); + } + catch (Exception e) + { + throw new IOException("error processing stream: " + e.toString()); + } + + if (maxBuf == 0) // not enough bytes read for first block... + { + return nextChunk(); + } + } + + return maxBuf; + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an <code>int</code> in the range + * <code>0</code> to <code>255</code>. If no byte is available + * because the end of the stream has been reached, the value + * <code>-1</code> is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + * + * @return the next byte of data, or <code>-1</code> if the end of the + * stream is reached. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public int read() + throws IOException + { + if (bufOff == maxBuf) + { + if (nextChunk() < 0) + { + return -1; + } + } + + return buf[bufOff++] & 0xff; + } + + /** + * Reads up to <code>b.length</code> bytes of data from this input + * stream into an array of bytes. + * <p> + * The <code>read</code> method of <code>InputStream</code> calls + * the <code>read</code> method of three arguments with the arguments + * <code>b</code>, <code>0</code>, and <code>b.length</code>. + * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * <code>-1</code> is there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + * @see #read(byte[], int, int) + */ + public int read( + byte[] b) + throws IOException + { + return read(b, 0, b.length); + } + + /** + * Reads up to <code>len</code> bytes of data from this input stream + * into an array of bytes. This method blocks until some input is + * available. If the first argument is <code>null,</code> up to + * <code>len</code> bytes are read and discarded. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or <code>-1</code> + * if there is no more data because the end of the stream has been reached. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + * @see #read() + */ + public int read( + byte[] b, + int off, + int len) + throws IOException + { + if (bufOff == maxBuf) + { + if (nextChunk() < 0) + { + return -1; + } + } + + int available = maxBuf - bufOff; + + if (len > available) + { + System.arraycopy(buf, bufOff, b, off, available); + bufOff = maxBuf; + + return available; + } + else + { + System.arraycopy(buf, bufOff, b, off, len); + bufOff += len; + + return len; + } + } + + /** + * Skips <code>n</code> bytes of input from the bytes that can be read + * from this input stream without blocking. + * <p> + * Fewer bytes than requested might be skipped. + * The actual number of bytes skipped is equal to <code>n</code> or + * the result of a call to <a href = "#available()"><code>available</code></a>, + * whichever is smaller. + * If <code>n</code> is less than zero, no bytes are skipped. + * <p> + * The actual number of bytes skipped is returned. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public long skip( + long n) + throws IOException + { + if (n <= 0) + { + return 0; + } + + int available = maxBuf - bufOff; + + if (n > available) + { + bufOff = maxBuf; + + return available; + } + else + { + bufOff += (int)n; + + return (int)n; + } + } + + /** + * Returns the number of bytes that can be read from this input + * stream without blocking. The <code>available</code> method of + * <code>InputStream</code> returns <code>0</code>. This method + * <B>should</B> be overridden by subclasses. + * + * @return the number of bytes that can be read from this input stream + * without blocking. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public int available() + throws IOException + { + return maxBuf - bufOff; + } + + /** + * Closes this input stream and releases any system resources + * associated with the stream. + * <p> + * The <code>close</code> method of <code>CipherInputStream</code> + * calls the <code>close</code> method of its underlying input + * stream. + * + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public void close() + throws IOException + { + super.close(); + } + + /** + * Tests if this input stream supports the <code>mark</code> + * and <code>reset</code> methods, which it does not. + * + * @return <code>false</code>, since this class does not support the + * <code>mark</code> and <code>reset</code> methods. + * @since JCE1.2 + * @see #mark(int) + * @see #reset() + */ + public boolean markSupported() + { + return false; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherOutputStream.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherOutputStream.java new file mode 100644 index 000000000..ef2db07f5 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherOutputStream.java @@ -0,0 +1,191 @@ +package javax.crypto; + +import java.io.OutputStream; +import java.io.IOException; +import java.io.FilterOutputStream; + +/** + * A CipherOutputStream is composed of an OutputStream and a Cipher so + * that write() methods first process the data before writing them out + * to the underlying OutputStream. The cipher must be fully + * initialized before being used by a CipherOutputStream. + * <p> + * For example, if the cipher is initialized for encryption, the + * CipherOutputStream will attempt to encrypt data before writing out the + * encrypted data. + * <p> + * This class adheres strictly to the semantics, especially the + * failure semantics, of its ancestor classes + * java.io.OutputStream and java.io.FilterOutputStream. This class + * has exactly those methods specified in its ancestor classes, and + * overrides them all. Moreover, this class catches all exceptions + * that are not thrown by its ancestor classes. + * <p> + * It is crucial for a programmer using this class not to use + * methods that are not defined or overriden in this class (such as a + * new method or constructor that is later added to one of the super + * classes), because the design and implementation of those methods + * are unlikely to have considered security impact with regard to + * CipherOutputStream. + * + * @since JCE1.2 + * @see OutputStream + * @see FilterOutputStream + * @see Cipher + * @see CipherInputStream + */ +public class CipherOutputStream + extends FilterOutputStream +{ + private Cipher c; + + private byte[] oneByte = new byte[1]; + + /** + * Constructs a CipherOutputStream from an OutputStream and a + * Cipher. + */ + public CipherOutputStream( + OutputStream os, + Cipher c) + { + super(os); + this.c = c; + } + + /** + * Constructs a CipherOutputStream from an OutputStream without + * specifying a Cipher. This has the effect of constructing a + * CipherOutputStream using a NullCipher. + */ + protected CipherOutputStream( + OutputStream os) + { + this(os, new NullCipher()); + } + + /** + * Writes the specified byte to this output stream. + * + * @param b the <code>byte</code>. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public void write( + int b) + throws IOException + { + oneByte[0] = (byte)b; + + byte[] bytes = c.update(oneByte, 0, 1); + + if (bytes != null) + { + out.write(bytes, 0, bytes.length); + } + } + + /** + * Writes <code>b.length</code> bytes from the specified byte array + * to this output stream. + * <p> + * The <code>write</code> method of + * <code>CipherOutputStream</code> calls the <code>write</code> + * method of three arguments with the three arguments + * <code>b</code>, <code>0</code>, and <code>b.length</code>. + * + * @param b the data. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + * @see #write(byte[], int, int) + */ + public void write( + byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + /** + * Writes <code>len</code> bytes from the specified byte array + * starting at offset <code>off</code> to this output stream. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public void write( + byte[] b, + int off, + int len) + throws IOException + { + byte[] bytes = c.update(b, off, len); + + if (bytes != null) + { + out.write(bytes, 0, bytes.length); + } + } + + /** + * Flushes this output stream by forcing any buffered output bytes + * that have already been processed by the encapsulated cipher object + * to be written out. + * + * <p> + * Any bytes buffered by the encapsulated cipher + * and waiting to be processed by it will not be written out. For example, + * if the encapsulated cipher is a block cipher, and the total number of + * bytes written using one of the <code>write</code> methods is less than + * the cipher's block size, no bytes will be written out. + * + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public void flush() + throws IOException + { + super.flush(); + } + + /** + * Closes this output stream and releases any system resources + * associated with this stream. + * <p> + * This method invokes the <code>doFinal</code> method of the encapsulated + * cipher object, which causes any bytes buffered by the encapsulated + * cipher to be processed. The result is written out by calling the + * <code>flush</code> method of this output stream. + * <p> + * This method resets the encapsulated cipher object to its initial state + * and calls the <code>close</code> method of the underlying output + * stream. + * + * @exception IOException if an I/O error occurs. + * @since JCE1.2 + */ + public void close() + throws IOException + { + try + { + byte[] bytes = c.doFinal(); + + if (bytes != null) + { + out.write(bytes, 0, bytes.length); + } + } + catch (Exception e) + { + throw new IOException("Error closing stream: " + e.toString()); + } + + flush(); + + super.close(); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherSpi.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherSpi.java new file mode 100644 index 000000000..09ff01e2c --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/CipherSpi.java @@ -0,0 +1,606 @@ +package javax.crypto; + +import java.security.Key; +import java.security.SecureRandom; +import java.security.InvalidKeyException; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) + * for the <code>Cipher</code> class. + * All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation + * of a particular cipher algorithm. + * <p> + * In order to create an instance of <code>Cipher</code>, which + * encapsulates an instance of this <code>CipherSpi</code> class, an + * application calls one of the + * <a href = "Cipher.html#getInstance(java.lang.String)">getInstance</a> + * factory methods of the + * <a href = "Cipher.html">Cipher</a> engine class and specifies the requested + * <i>transformation</i>. + * Optionally, the application may also specify the name of a provider. + * <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>A provider may supply a separate class for each combination + * of <i>algorithm/mode/padding</i>, or may decide to provide more generic + * classes representing sub-transformations corresponding to + * <i>algorithm</i> or <i>algorithm/mode</i> or <i>algorithm//padding</i> + * (note the double slashes), + * in which case the requested mode and/or padding are set automatically by + * the <code>getInstance</code> methods of <code>Cipher</code>, which invoke + * the <a href = "#engineSetMode(java.lang.String)">engineSetMode</a> and + * <a href = "#engineSetPadding(java.lang.String)">engineSetPadding</a> + * methods of the provider's subclass of <code>CipherSpi</code>. + * + * <p>A <code>Cipher</code> property in a provider master class may have one of + * the following formats: + * + * <ul> + * + * <li> + * <pre> + * // provider's subclass of "CipherSpi" implements "algName" with + * // pluggable mode and padding + * <code>Cipher.</code><i>algName</i> + * </pre> + * + * <li> + * <pre> + * // provider's subclass of "CipherSpi" implements "algName" in the + * // specified "mode", with pluggable padding + * <code>Cipher.</code><i>algName/mode</i> + * </pre> + * + * <li> + * <pre> + * // provider's subclass of "CipherSpi" implements "algName" with the + * // specified "padding", with pluggable mode + * <code>Cipher.</code><i>algName//padding</i> + * </pre> + * + * <li> + * <pre> + * // provider's subclass of "CipherSpi" implements "algName" with the + * // specified "mode" and "padding" + * <code>Cipher.</code><i>algName/mode/padding</i> + * </pre> + * + * </ul> + * + * <p>For example, a provider may supply a subclass of <code>CipherSpi</code> + * that implements <i>DES/ECB/PKCS5Padding</i>, one that implements + * <i>DES/CBC/PKCS5Padding</i>, one that implements + * <i>DES/CFB/PKCS5Padding</i>, and yet another one that implements + * <i>DES/OFB/PKCS5Padding</i>. That provider would have the following + * <code>Cipher</code> properties in its master class:<p> + * + * <ul> + * + * <li> + * <pre> + * <code>Cipher.</code><i>DES/ECB/PKCS5Padding</i> + * </pre> + * + * <li> + * <pre> + * <code>Cipher.</code><i>DES/CBC/PKCS5Padding</i> + * </pre> + * + * <li> + * <pre> + * <code>Cipher.</code><i>DES/CFB/PKCS5Padding</i> + * </pre> + * + * <li> + * <pre> + * <code>Cipher.</code><i>DES/OFB/PKCS5Padding</i> + * </pre> + * + * </ul> + * + * <p>Another provider may implement a class for each of the above modes + * (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>, + * and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>, + * and a generic <i>DES</i> class that subclasses from <code>CipherSpi</code>. + * That provider would have the following + * <code>Cipher</code> properties in its master class:<p> + * + * <ul> + * + * <li> + * <pre> + * <code>Cipher.</code><i>DES</i> + * </pre> + * + * </ul> + * + * <p>The <code>getInstance</code> factory method of the <code>Cipher</code> + * engine class follows these rules in order to instantiate a provider's + * implementation of <code>CipherSpi</code> for a + * transformation of the form "<i>algorithm</i>": + * + * <ol> + * <li> + * Check if the provider has registered a subclass of <code>CipherSpi</code> + * for the specified "<i>algorithm</i>". + * <p>If the answer is YES, instantiate this + * class, for whose mode and padding scheme default values (as supplied by + * the provider) are used. + * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code> + * exception. + * </ol> + * + * <p>The <code>getInstance</code> factory method of the <code>Cipher</code> + * engine class follows these rules in order to instantiate a provider's + * implementation of <code>CipherSpi</code> for a + * transformation of the form "<i>algorithm/mode/padding</i>": + * + * <ol> + * <li> + * Check if the provider has registered a subclass of <code>CipherSpi</code> + * for the specified "<i>algorithm/mode/padding</i>" transformation. + * <p>If the answer is YES, instantiate it. + * <p>If the answer is NO, go to the next step.<p> + * <li> + * Check if the provider has registered a subclass of <code>CipherSpi</code> + * for the sub-transformation "<i>algorithm/mode</i>". + * <p>If the answer is YES, instantiate it, and call + * <code>engineSetPadding(<i>padding</i>)</code> on the new instance. + * <p>If the answer is NO, go to the next step.<p> + * <li> + * Check if the provider has registered a subclass of <code>CipherSpi</code> + * for the sub-transformation "<i>algorithm//padding</i>" (note the double + * slashes). + * <p>If the answer is YES, instantiate it, and call + * <code>engineSetMode(<i>mode</i>)</code> on the new instance. + * <p>If the answer is NO, go to the next step.<p> + * <li> + * Check if the provider has registered a subclass of <code>CipherSpi</code> + * for the sub-transformation "<i>algorithm</i>". + * <p>If the answer is YES, instantiate it, and call + * <code>engineSetMode(<i>mode</i>)</code> and + * <code>engineSetPadding(<i>padding</i>)</code> on the new instance. + * <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code> + * exception. + * </ol> + * + * @see KeyGenerator + * @see SecretKey + */ +public abstract class CipherSpi +{ + public CipherSpi() + { + } + + /** + * Sets the mode of this cipher. + * + * @param mode the cipher mode + * @exception NoSuchAlgorithmException if the requested cipher mode does not exist + */ + protected abstract void engineSetMode( + String mode) + throws NoSuchAlgorithmException; + + /** + * Sets the padding mechanism of this cipher. + * + * @param padding the padding mechanism + * @exception NoSuchPaddingException if the requested padding mechanism does not exist + */ + protected abstract void engineSetPadding( + String padding) + throws NoSuchPaddingException; + + /** + * Returns the block size (in bytes). + * + * @return the block size (in bytes), or 0 if the underlying algorithm is not a block cipher + */ + protected abstract int 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) + */ + protected abstract int engineGetOutputSize( + int inputLen); + + /** + * Returns the initialization vector (IV) in a new buffer. + * <p> + * This is useful in the context of password-based encryption or + * decryption, where the IV is derived from a user-provided passphrase. + * + * @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. + */ + protected abstract byte[] 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. + */ + protected abstract AlgorithmParameters engineGetParameters(); + + /** + * 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. + */ + protected abstract void engineInit( + int opmode, + Key key, + SecureRandom random) + throws InvalidKeyException; + + /** + * 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 = "#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 params the algorithm parameters + * @param random the source of randomness + * @exception InvalidKeyException if the given key is inappropriate for initializing this cipher + * @exception InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate + * for this cipher, or if this cipher is being initialized for decryption and requires + * algorithm parameters and <code>params</code> is null. + */ + protected abstract void engineInit( + int opmode, + Key key, + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException; + + /** + * 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 = "#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 params the algorithm parameters + * @param random the source of randomness + * @exception InvalidKeyException if the given key is inappropriate for initializing this cipher + * @exception InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate + * for this cipher, or if this cipher is being initialized for decryption and requires + * algorithm parameters and <code>params</code> is null. + */ + protected abstract void engineInit( + int opmode, + Key key, + AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException; + + /** + * 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. + * + * @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. + */ + protected abstract byte[] engineUpdate( + byte[] input, + int inputOffset, + int 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, 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. + * + * @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 ShortBufferException if the given output buffer is too small to hold the result + */ + protected abstract int engineUpdate( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + throws ShortBufferException; + + /** + * 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>engineInit</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>engineInit</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 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 + */ + protected abstract byte[] engineDoFinal( + byte[] input, + int inputOffset, + int inputLen) + throws IllegalBlockSizeException, BadPaddingException; + + /** + * 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. + * <p> + * A call to this method resets this cipher object to the state + * it was in when previously initialized via a call to + * <code>engineInit</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>engineInit</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 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 + */ + protected abstract int engineDoFinal( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException; + + /** + * Wrap a key. + * <p> + * This concrete method has been added to this previously-defined + * abstract class. (For backwards compatibility, it cannot be abstract.) + * It may be overridden by a provider to wrap a key. + * Such an override is expected to throw an IllegalBlockSizeException or + * InvalidKeyException (under the specified circumstances), + * if the given key cannot be wrapped. + * If this method is not overridden, it always throws an + * UnsupportedOperationException. + * + * @param key the key to be wrapped. + * @return the wrapped key. + * @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 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). + */ + protected byte[] engineWrap( + Key key) + throws IllegalBlockSizeException, InvalidKeyException + { + throw new UnsupportedOperationException("Underlying cipher does not support key wrapping"); + } + + /** + * Unwrap a previously wrapped key. + * + * <p>This concrete method has been added to this previously-defined + * abstract class. (For backwards compatibility, it cannot be abstract.) + * It may be overridden by a provider to unwrap a previously wrapped key. + * Such an override is expected to throw an InvalidKeyException if + * the given wrapped key cannot be unwrapped. + * If this method is not overridden, it always throws an + * UnsupportedOperationException. + * + * @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 is one of <code>SECRET_KEY</code>, + * <code>PRIVATE_KEY</code>, or <code>PUBLIC_KEY</code>. + * @return the unwrapped key. + * @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>. + */ + protected java.security.Key engineUnwrap( + byte[] wrappedKey, + String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException + { + throw new UnsupportedOperationException("Underlying cipher does not support key unwrapping"); + } + + /** + * Returns the key size of the given key object. + * <p> + * This concrete method has been added to this previously-defined + * abstract class. It throws an <code>UnsupportedOperationException</code> + * if it is not overridden by the provider. + * + * @param key the key object. + * @return the key size of the given key object. + * @exception InvalidKeyException if <code>key</code> is invalid. + */ + protected int engineGetKeySize( + Key key) + throws InvalidKeyException + { + throw new UnsupportedOperationException("Key size unavailable"); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java new file mode 100644 index 000000000..19f22ebe6 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java @@ -0,0 +1,234 @@ +package javax.crypto; + +import java.io.*; + +import java.security.*; +import java.security.spec.*; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * This class implements the <code>EncryptedPrivateKeyInfo</code> type + * as defined in PKCS #8. + * <p>Its ASN.1 definition is as follows: + * + * <pre> + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm AlgorithmIdentifier, + * encryptedData OCTET STRING } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * </pre> + */ +public class EncryptedPrivateKeyInfo +{ + private org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo infoObj; + private AlgorithmParameters algP; + + /* + * Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from + * its ASN.1 encoding. + * + * @param encoded the ASN.1 encoding of this object. + * @exception NullPointerException if the <code>encoded</code> is null. + * @exception IOException if error occurs when parsing the ASN.1 encoding. + */ + public EncryptedPrivateKeyInfo( + byte[] encoded) + throws NullPointerException, IOException + { + if (encoded == null) + { + throw new NullPointerException("parameters null"); + } + + ByteArrayInputStream bIn = new ByteArrayInputStream(encoded); + ASN1InputStream dIn = new ASN1InputStream(bIn); + + infoObj = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance((ASN1Sequence)dIn.readObject()); + + try + { + algP = this.getParameters(); + } + catch (NoSuchAlgorithmException e) + { + throw new IOException("can't create parameters: " + e.toString()); + } + } + + /* + * Constructs an <code>EncryptedPrivateKeyInfo</code> from the + * encryption algorithm name and the encrypted data. + * <p>Note: the <code>encrypedData</code> is cloned when constructing + * this object. + * <p> + * If encryption algorithm has associated parameters use the constructor + * with AlgorithmParameters as the parameter. + * + * @param algName algorithm name. + * @param encryptedData encrypted data. + * @exception NullPointerException if <code>algName</code> or <code>encryptedData</code> is null. + * @exception IllegalArgumentException if <code>encryptedData</code> is empty, i.e. 0-length. + * @exception NoSuchAlgorithmException if the specified algName is not supported. + */ + public EncryptedPrivateKeyInfo( + String algName, + byte[] encryptedData) + throws NullPointerException, IllegalArgumentException, NoSuchAlgorithmException + { + if (algName == null || encryptedData == null) + { + throw new NullPointerException("parameters null"); + } + + org.spongycastle.asn1.x509.AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(new DERObjectIdentifier(algName), null); + + infoObj = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, (byte[])encryptedData.clone()); + algP = this.getParameters(); + } + + /** + * Constructs an <code>EncryptedPrivateKeyInfo</code> from the + * encryption algorithm parameters and the encrypted data. + * <p>Note: the <code>encrypedData</code> is cloned when constructing + * this object. + * + * @param algParams the algorithm parameters for the encryption + * algorithm. <code>algParams.getEncoded()</code> should return + * the ASN.1 encoded bytes of the <code>parameters</code> field + * of the <code>AlgorithmIdentifer</code> component of the + * <code>EncryptedPrivateKeyInfo</code> type. + * @param encryptedData encrypted data. + * @exception NullPointerException if <code>algParams</code> or <code>encryptedData</code> is null. + * @exception IllegalArgumentException if <code>encryptedData</code> is empty, i.e. 0-length. + * @exception NoSuchAlgorithmException if the specified algName of the specified <code>algParams</code> parameter is not supported. + */ + public EncryptedPrivateKeyInfo( + AlgorithmParameters algParams, + byte[] encryptedData) + throws NullPointerException, IllegalArgumentException, NoSuchAlgorithmException + { + if (algParams == null || encryptedData == null) + { + throw new NullPointerException("parameters null"); + } + + org.spongycastle.asn1.x509.AlgorithmIdentifier kAlgId = null; + + try + { + ByteArrayInputStream bIn = new ByteArrayInputStream(algParams.getEncoded()); + ASN1InputStream dIn = new ASN1InputStream(bIn); + + kAlgId = new AlgorithmIdentifier( + new DERObjectIdentifier(algParams.getAlgorithm()), dIn.readObject()); + } + catch (IOException e) + { + throw new IllegalArgumentException("error in encoding: " + e.toString()); + } + + infoObj = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, (byte[])encryptedData.clone()); + algP = this.getParameters(); + } + + /** + * Returns the encryption algorithm. + * + * @returns the algorithm name. + */ + public String getAlgName() + { + return infoObj.getEncryptionAlgorithm().getObjectId().getId(); + } + + private AlgorithmParameters getParameters() + throws NoSuchAlgorithmException + { + AlgorithmParameters ap = AlgorithmParameters.getInstance(this.getAlgName()); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + try + { + dOut.writeObject(infoObj.getEncryptionAlgorithm().getParameters()); + dOut.close(); + + ap.init(bOut.toByteArray()); + } + catch (IOException e) + { + throw new NoSuchAlgorithmException("unable to parse parameters"); + } + + return ap; + } + + /** + * Returns the algorithm parameters used by the encryption algorithm. + * + * @returns the algorithm parameters. + */ + public AlgorithmParameters getAlgParameters() + { + return algP; + } + + /** + * Returns a copy of the encrypted data. + * + * @returns a copy of the encrypted data. + */ + public byte[] getEncryptedData() + { + return infoObj.getEncryptedData(); + } + + /** + * Extract the enclosed PKCS8EncodedKeySpec object from the + * encrypted data and return it. + * + * @return the PKCS8EncodedKeySpec object. + * @exception InvalidKeySpecException if the given cipher is + * inappropriate for the encrypted data or the encrypted + * data is corrupted and cannot be decrypted. + */ + public PKCS8EncodedKeySpec getKeySpec( + Cipher c) + throws InvalidKeySpecException + { + try + { + return new PKCS8EncodedKeySpec(c.doFinal(this.getEncryptedData())); + } + catch (Exception e) + { + throw new InvalidKeySpecException("can't get keySpec: " + e.toString()); + } + } + + /** + * Returns the ASN.1 encoding of this object. + * + * @returns the ASN.1 encoding. + * @throws IOException if error occurs when constructing its ASN.1 encoding. + */ + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + dOut.writeObject(infoObj); + dOut.close(); + + return bOut.toByteArray(); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/ExemptionMechanism.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/ExemptionMechanism.java new file mode 100644 index 000000000..49846ee92 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/ExemptionMechanism.java @@ -0,0 +1,9 @@ +package javax.crypto; + +/** + * this is a place holder class, no exemption mechanism facility is + * required in this modified version of the JCE + */ +public class ExemptionMechanism +{ +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/ExemptionMechanismException.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/ExemptionMechanismException.java new file mode 100644 index 000000000..e17ab0cf1 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/ExemptionMechanismException.java @@ -0,0 +1,34 @@ +package javax.crypto; + +import java.security.GeneralSecurityException; + +/** + * This is the generic ExemptionMechanism exception. + * + */ +public class ExemptionMechanismException + extends GeneralSecurityException +{ + private static final long serialVersionUID = 1572699429277957109L; + + /** + * Constructs a ExemptionMechanismException with no detailed message. + * (A detailed message is a String that describes this particular exception.) + */ + public ExemptionMechanismException() + { + } + + /** + * Constructs a ExemptionMechanismException with the specified + * detailed message. (A detailed message is a String that describes + * this particular exception.) + * + * @param msg the detailed message. + */ + public ExemptionMechanismException( + String msg) + { + super(msg); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java new file mode 100644 index 000000000..5cd4176b2 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java @@ -0,0 +1,36 @@ +package javax.crypto; + +import java.security.GeneralSecurityException; + +/** + * This exception is thrown when the length of data provided to a block + * cipher is incorrect, i.e., does not match the block size of the cipher. + * + */ +public class IllegalBlockSizeException + extends GeneralSecurityException +{ + private static final long serialVersionUID = -1965144811953540392L; + + /** + * Constructs an IllegalBlockSizeException with no detail message. + * (A detail message is a String that describes this particular + * exception.) + */ + public IllegalBlockSizeException() + { + } + + /** + * Constructs an IllegalBlockSizeException with the specified + * detail message. (A detail message is a String that describes + * this particular exception.) + * + * @param msg the detail message. + */ + public IllegalBlockSizeException( + String msg) + { + super(msg); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/JCEUtil.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/JCEUtil.java new file mode 100644 index 000000000..913c01b03 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/JCEUtil.java @@ -0,0 +1,202 @@ +package javax.crypto; + +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.util.Locale; + +class JCEUtil +{ + static class Implementation + { + Object engine; + Provider provider; + + Implementation( + Object engine, + Provider provider) + { + this.engine = engine; + this.provider = provider; + } + + Object getEngine() + { + return engine; + } + + Provider getProvider() + { + return provider; + } + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + * + * @return null if no algorithm found, an Implementation if it is. + */ + static private Implementation findImplementation( + String baseName, + String algorithm, + Provider prov) + { + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + Class cls; + ClassLoader clsLoader = prov.getClass().getClassLoader(); + + if (clsLoader != null) + { + cls = clsLoader.loadClass(className); + } + else + { + cls = Class.forName(className); + } + + return new Implementation(cls.newInstance(), prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!"); + } + catch (Exception e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!"); + } + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. + * If the provider is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * @exception NoSuchProviderException if a provider is specified and not found. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + String provider) + throws NoSuchProviderException + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + // + // try case insensitive + // + Implementation imp = findImplementation(baseName, algorithm.toUpperCase(Locale.ENGLISH), prov[i]); + if (imp != null) + { + return imp; + } + + imp = findImplementation(baseName, algorithm, prov[i]); + if (imp != null) + { + return imp; + } + } + } + else + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + " not found"); + } + + // + // try case insensitive + // + Implementation imp = findImplementation(baseName, algorithm.toUpperCase(Locale.ENGLISH), prov); + if (imp != null) + { + return imp; + } + + return findImplementation(baseName, algorithm, prov); + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. + * If the provider is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * @exception NoSuchProviderException if a provider is specified and not found. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + Provider provider) + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + // + // try case insensitive + // + Implementation imp = findImplementation(baseName, algorithm.toUpperCase(Locale.ENGLISH), prov[i]); + if (imp != null) + { + return imp; + } + + imp = findImplementation(baseName, algorithm, prov[i]); + if (imp != null) + { + return imp; + } + } + } + else + { + // + // try case insensitive + // + Implementation imp = findImplementation(baseName, algorithm.toUpperCase(Locale.ENGLISH), provider); + if (imp != null) + { + return imp; + } + + return findImplementation(baseName, algorithm, provider); + } + + return null; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyAgreement.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyAgreement.java new file mode 100644 index 000000000..6e8d768bd --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyAgreement.java @@ -0,0 +1,394 @@ +package javax.crypto; + +import java.security.Key; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.InvalidKeyException; +import java.security.NoSuchProviderException; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class provides the functionality of a key agreement (or key + * exchange) protocol. + * The keys involved in establishing a shared secret are created by one of the + * key generators (<code>KeyPairGenerator</code> or + * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from + * an intermediate phase of the key agreement protocol + * (see <a href = "#doPhase(java.security.Key, boolean)">doPhase</a>). + * + * For each of the correspondents in the key exchange, <code>doPhase</code> + * needs to be called. For example, if this key exchange is with one other + * party, <code>doPhase</code> needs to be called once, with the + * <code>lastPhase</code> flag set to <code>true</code>. + * If this key exchange is + * with two other parties, <code>doPhase</code> needs to be called twice, + * the first time setting the <code>lastPhase</code> flag to + * <code>false</code>, and the second time setting it to <code>true</code>. + * There may be any number of parties involved in a key exchange. + * + * @see KeyGenerator + * @see SecretKey + */ +public class KeyAgreement +{ + KeyAgreementSpi keyAgreeSpi; + Provider provider; + String algorithm; + + /** + * Creates a KeyAgreement object. + * + * @param keyAgreeSpi the delegate + * @param provider the provider + * @param algorithm the algorithm + */ + protected KeyAgreement( + KeyAgreementSpi keyAgreeSpi, + Provider provider, + String algorithm) + { + this.keyAgreeSpi = keyAgreeSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns the algorithm name of this <code>KeyAgreement</code> object. + * <p> + * This is the same name that was specified in one of the + * <code>getInstance</code> calls that created this + * <code>KeyAgreement</code> object. + * + * @return the algorithm name of this <code>KeyAgreement</code> object. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Generates a <code>KeyAgreement</code> object that implements the + * specified key agreement algorithm. + * If the default provider package provides an implementation of the + * requested key agreement algorithm, an instance of + * <code>KeyAgreement</code> containing that implementation is returned. + * If the algorithm is not available in the default provider package, + * other provider packages are searched. + * + * @param algorithm the standard name of the requested key agreement algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @return the new <code>KeyAgreement</code> object + * @exception NoSuchAlgorithmException if the specified algorithm is not + * available in the default provider package or any of the other provider + * packages that were searched. + */ + public static final KeyAgreement getInstance( + String algorithm) + throws NoSuchAlgorithmException + { + try + { + JCEUtil.Implementation imp = JCEUtil.getImplementation("KeyAgreement", algorithm, (String) null); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + KeyAgreement keyAgree = new KeyAgreement((KeyAgreementSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyAgree; + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + /** + * Generates a <code>KeyAgreement</code> object for the specified key + * agreement algorithm from the specified provider. + * + * @param algorithm the standard name of the requested key agreement algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @param provider the provider + * @return the new <code>KeyAgreement</code> object + * @exception NoSuchAlgorithmException if the specified algorithm is not + * available from the specified provider. + */ + public static final KeyAgreement getInstance( + String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to KeyAgreement.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("KeyAgreement", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + KeyAgreement keyAgree = new KeyAgreement((KeyAgreementSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyAgree; + } + + /** + * Generates a <code>KeyAgreement</code> object for the specified key + * agreement algorithm from the specified provider. + * + * @param algorithm the standard name of the requested key agreement algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @param provider the name of the provider + * @return the new <code>KeyAgreement</code> object + * @exception NoSuchAlgorithmException if the specified algorithm is not + * available from the specified provider. + * @exception NoSuchProviderException if the specified provider has not + * been configured. + */ + public static final KeyAgreement getInstance( + String algorithm, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to KeyAgreement.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("KeyAgreement", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + KeyAgreement keyAgree = new KeyAgreement((KeyAgreementSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyAgree; + } + + /** + * Returns the provider of this <code>KeyAgreement</code> object. + * + * @return the provider of this <code>KeyAgreement</code> object + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Initializes this key agreement with the given key, which is required to + * contain all the algorithm parameters required for this key agreement. + * <p> + * If this key agreement requires any random bytes, 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.) + * + * @param key the party's private information. For example, in the case + * of the Diffie-Hellman key agreement, this would be the party's own + * Diffie-Hellman private key. + * @exception InvalidKeyException if the given key is + * inappropriate for this key agreement, e.g., is of the wrong type or + * has an incompatible algorithm type. + */ + public final void init( + Key key) + throws InvalidKeyException + { + keyAgreeSpi.engineInit(key, null); + } + + /** + * Initializes this key agreement with the given key and source of + * randomness. The given key is required to contain all the algorithm + * parameters required for this key agreement. + * <p> + * If the key agreement algorithm requires random bytes, it gets them + * from the given source of randomness, <code>random</code>. + * However, if the underlying + * algorithm implementation does not require any random bytes, + * <code>random</code> is ignored. + * + * @param key the party's private information. For example, in the case + * of the Diffie-Hellman key agreement, this would be the party's own + * Diffie-Hellman private key. + * @param random the source of randomness + * @exception InvalidKeyException if the given key is + * inappropriate for this key agreement, e.g., is of the wrong type or + * has an incompatible algorithm type. + */ + public final void init( + Key key, + SecureRandom random) + throws InvalidKeyException + { + keyAgreeSpi.engineInit(key, random); + } + + /** + * Initializes this key agreement with the given key and set of + * algorithm parameters. + * <p> + * If this key agreement requires any random bytes, 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.) + * + * @param key the party's private information. For example, in the case + * of the Diffie-Hellman key agreement, this would be the party's own + * Diffie-Hellman private key. + * @param params the key agreement parameters + * @exception InvalidKeyException if the given key is inappropriate for this + * key agreement, e.g., is of the wrong type or has an incompatible algorithm type. + * @exception InvalidAlgorithmParameterException if the given parameters + * are inappropriate for this key agreement. + */ + public final void init( + Key key, + AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + keyAgreeSpi.engineInit(key, params, null); + } + + /** + * Initializes this key agreement with the given key, set of + * algorithm parameters, and source of randomness. + * + * @param key the party's private information. For example, in the case + * of the Diffie-Hellman key agreement, this would be the party's own + * Diffie-Hellman private key. + * @param params the key agreement parameters + * @param random the source of randomness + * @exception InvalidKeyException if the given key is + * inappropriate for this key agreement, e.g., is of the wrong type or + * has an incompatible algorithm type. + * @exception InvalidAlgorithmParameterException if the given parameters + * are inappropriate for this key agreement. + */ + public final void init( + Key key, + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + keyAgreeSpi.engineInit(key, params, random); + } + + /** + * Executes the next phase of this key agreement with the given + * key that was received from one of the other parties involved in this key + * agreement. + * + * @param key the key for this phase. For example, in the case of + * Diffie-Hellman between 2 parties, this would be the other party's + * Diffie-Hellman public key. + * @param lastPhase flag which indicates whether or not this is the last + * phase of this key agreement. + * @return the (intermediate) key resulting from this phase, or null + * if this phase does not yield a key + * @exception InvalidKeyException if the given key is inappropriate for this phase. + * @exception IllegalStateException if this key agreement has not been + * initialized. + */ + public final Key doPhase( + Key key, + boolean lastPhase) + throws InvalidKeyException, IllegalStateException + { + return keyAgreeSpi.engineDoPhase(key, lastPhase); + } + + /** + * Generates the shared secret and returns it in a new buffer. + * <p> + * This method resets this <code>KeyAgreement</code> object, so that it + * can be reused for further key agreements. Unless this key agreement is + * reinitialized with one of the <code>init</code> methods, the same + * private information and algorithm parameters will be used for + * subsequent key agreements. + * + * @return the new buffer with the shared secret + * @exception IllegalStateException if this key agreement has not been completed yet + */ + public final byte[] generateSecret() + throws IllegalStateException + { + return keyAgreeSpi.engineGenerateSecret(); + } + + /** + * Generates the shared secret, and places it into the buffer + * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive. + * <p> + * If the <code>sharedSecret</code> buffer is too small to hold the + * result, a <code>ShortBufferException</code> is thrown. + * In this case, this call should be repeated with a larger output buffer. + * <p> + * This method resets this <code>KeyAgreement</code> object, so that it + * can be reused for further key agreements. Unless this key agreement is + * reinitialized with one of the <code>init</code> methods, the same + * private information and algorithm parameters will be used for + * subsequent key agreements. + * + * @param sharedSecret the buffer for the shared secret + * @param offset the offset in <code>sharedSecret</code> where the + * shared secret will be stored + * @return the number of bytes placed into <code>sharedSecret</code> + * @exception IllegalStateException if this key agreement has not been + * completed yet + * @exception ShortBufferException if the given output buffer is too small + * to hold the secret + */ + public final int generateSecret( + byte[] sharedSecret, + int offset) + throws IllegalStateException, ShortBufferException + { + return keyAgreeSpi.engineGenerateSecret(sharedSecret, offset); + } + + /** + * Creates the shared secret and returns it as a <code>SecretKey</code> + * object of the specified algorithm. + * <p> + * This method resets this <code>KeyAgreement</code> object, so that it + * can be reused for further key agreements. Unless this key agreement is + * reinitialized with one of the <code>init</code> methods, the same + * private information and algorithm parameters will be used for + * subsequent key agreements. + * + * @param algorithm the requested secret-key algorithm + * @return the shared secret key + * @exception IllegalStateException if this key agreement has not been + * completed yet + * @exception NoSuchAlgorithmException if the specified secret-key + * algorithm is not available + * @exception InvalidKeyException if the shared secret-key material cannot + * be used to generate a secret key of the specified algorithm (e.g., + * the key material is too short) + */ + public final SecretKey generateSecret( + String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException + { + return keyAgreeSpi.engineGenerateSecret(algorithm); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyAgreementSpi.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyAgreementSpi.java new file mode 100644 index 000000000..b4569a1eb --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyAgreementSpi.java @@ -0,0 +1,159 @@ +package javax.crypto; + +import java.security.Key; +import java.security.SecureRandom; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidAlgorithmParameterException; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) + * for the <code>KeyAgreement</code> class. + * All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation + * of a particular key agreement algorithm. + * <p> + * The keys involved in establishing a shared secret are created by one of the + * key generators (<code>KeyPairGenerator</code> or <code>KeyGenerator</code>), + * a <code>KeyFactory</code>, or as a result from an intermediate phase of the key + * agreement protocol (see <a href = "#engineDoPhase(java.security.Key, boolean)">engineDoPhase</a>). + * <p> + * For each of the correspondents in the key exchange, <code>engineDoPhase</code> + * needs to be called. For example, if the key exchange is with one other + * party, <code>engineDoPhase</code> needs to be called once, with the + * <code>lastPhase</code> flag set to <code>true</code>. + * If the key exchange is with two other parties, <code>engineDoPhase</code> needs to be called twice, + * the first time setting the <code>lastPhase</code> flag to + * <code>false</code>, and the second time setting it to <code>true</code>. + * There may be any number of parties involved in a key exchange. + * + * @see KeyGenerator + * @see SecretKey + */ +public abstract class KeyAgreementSpi +{ + public KeyAgreementSpi() + { + } + + /** + * Initializes this key agreement with the given key and source of + * randomness. The given key is required to contain all the algorithm + * parameters required for this key agreement. + * <p> + * If the key agreement algorithm requires random bytes, it gets them + * from the given source of randomness, <code>random</code>. + * However, if the underlying + * algorithm implementation does not require any random bytes, + * <code>random</code> is ignored. + * + * @param key the party's private information. For example, in the case + * of the Diffie-Hellman key agreement, this would be the party's own Diffie-Hellman private key. + * @param random the source of randomness + * @exception InvalidKeyException if the given key is inappropriate for this key agreement, e.g., is + * of the wrong type or has an incompatible algorithm type. + */ + protected abstract void engineInit( + Key key, + SecureRandom random) + throws InvalidKeyException; + + /** + * Initializes this key agreement with the given key, set of + * algorithm parameters, and source of randomness. + * + * @param key the party's private information. For example, in the case + * of the Diffie-Hellman key agreement, this would be the party's own + * Diffie-Hellman private key. + * @param params the key agreement parameters + * @param random the source of randomness + * @exception InvalidKeyException if the given key is inappropriate for this key agreement, e.g., is of the + * wrong type or has an incompatible algorithm type. + * @exception InvalidAlgorithmParameterException if the given parameters are inappropriate for this key + * agreement. + */ + protected abstract void engineInit( + Key key, + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException; + + /** + * Executes the next phase of this key agreement with the given + * key that was received from one of the other parties involved in this key + * agreement. + * @param key the key for this phase. For example, in the case of + * Diffie-Hellman between 2 parties, this would be the other party's + * Diffie-Hellman public key. + * @param lastPhase flag which indicates whether or not this is the last + * phase of this key agreement. + * @return the (intermediate) key resulting from this phase, or null if this phase does not yield a key + * @exception InvalidKeyException if the given key is inappropriate for this phase. + * @exception IllegalStateException if this key agreement has not been initialized. + */ + protected abstract Key engineDoPhase( + Key key, + boolean lastPhase) + throws InvalidKeyException, IllegalStateException; + + /** + * Generates the shared secret and returns it in a new buffer. + * <p> + * This method resets this <code>KeyAgreementSpi</code> object, so that it + * can be reused for further key agreements. Unless this key agreement is + * reinitialized with one of the <code>engineInit</code> methods, the same + * private information and algorithm parameters will be used for + * subsequent key agreements. + * @return the new buffer with the shared secret + * @exception IllegalStateException if this key agreement has not been completed yet + */ + protected abstract byte[] engineGenerateSecret() + throws IllegalStateException; + + /** + * Generates the shared secret, and places it into the buffer + * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive. + * <p> + * If the <code>sharedSecret</code> buffer is too small to hold the result, + * a <code>ShortBufferException</code> is thrown. In this case, this call should be + * repeated with a larger output buffer. + * <p> + * This method resets this <code>KeyAgreementSpi</code> object, so that it + * can be reused for further key agreements. Unless this key agreement is + * reinitialized with one of the <code>engineInit</code> methods, the same + * private information and algorithm parameters will be used for subsequent key agreements. + * + * @param sharedSecret the buffer for the shared secret + * @param offset the offset in <code>sharedSecret</code> where the shared secret will be stored + * @return the number of bytes placed into <code>sharedSecret</code> + * @exception IllegalStateException if this key agreement has not been completed yet + * @exception ShortBufferException if the given output buffer is too small to hold the secret + */ + protected abstract int engineGenerateSecret( + byte[] sharedSecret, + int offset) + throws IllegalStateException, ShortBufferException; + + /** + * Creates the shared secret and returns it as a secret key object + * of the requested algorithm type. + * <p> + * This method resets this <code>KeyAgreementSpi</code> object, so that it + * can be reused for further key agreements. Unless this key agreement is + * reinitialized with one of the <code>engineInit</code> methods, the same + * private information and algorithm parameters will be used for + * subsequent key agreements. + * + * @param algorithm the requested secret key algorithm + * @return the shared secret key + * @exception IllegalStateException if this key agreement has not been completed yet + * @exception NoSuchAlgorithmException if the requested secret key algorithm is not available + * @exception InvalidKeyException if the shared secret key material cannot be used to generate + * a secret key of the requested algorithm type (e.g., the key material is too short) + */ + protected abstract SecretKey engineGenerateSecret( + String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException; +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyGenerator.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyGenerator.java new file mode 100644 index 000000000..19a34cedd --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyGenerator.java @@ -0,0 +1,302 @@ +package javax.crypto; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class provides the functionality of a (symmetric) key generator. + * <p> + * Key generators are constructed using one of the <code>getInstance</code> + * class methods of this class. + * <p> + * KeyGenerator objects are reusable, i.e., after a key has been + * generated, the same KeyGenerator object can be re-used to generate further + * keys. + * <p> + * There are two ways to generate a key: in an algorithm-independent manner, + * and in an algorithm-specific manner. The only difference between the two is + * the initialization of the object: + * + * <ul> + * <li><b>Algorithm-Independent Initialization</b> + * <p>All key generators share the concepts of a <i>keysize</i> and a + * <i>source of randomness</i>. + * There is an + * <a href = "#init(int, java.security.SecureRandom)">init</a> + * method in this KeyGenerator class that takes these two universally + * shared types of arguments. There is also one that takes just a + * <code>keysize</code> argument, and uses the SecureRandom implementation + * of the highest-priority installed provider as the source of randomness + * (or a system-provided source of randomness if none of the installed + * providers supply a SecureRandom implementation), and one that takes just a + * source of randomness. + * <p> + * Since no other parameters are specified when you call the above + * algorithm-independent <code>init</code> methods, it is up to the + * provider what to do about the algorithm-specific parameters (if any) to be + * associated with each of the keys. + * <p> + * <li><b>Algorithm-Specific Initialization</b> + * <p>For situations where a set of algorithm-specific parameters already + * exists, there are two + * <a href = "#init(java.security.spec.AlgorithmParameterSpec)">init</a> + * methods that have an <code>AlgorithmParameterSpec</code> + * argument. One also has a <code>SecureRandom</code> argument, while the + * other uses the SecureRandom implementation + * of the highest-priority installed provider as the source of randomness + * (or a system-provided source of randomness if none of the installed + * providers supply a SecureRandom implementation). + * </ul> + * + * <p>In case the client does not explicitly initialize the KeyGenerator + * (via a call to an <code>init</code> method), each provider must + * supply (and document) a default initialization. + * + * @see SecretKey + */ +public class KeyGenerator +{ + private KeyGeneratorSpi keyGenerator; + private Provider provider; + private String algorithm; + + /** + * Creates a KeyGenerator object. + * + * @param keyGenSpi the delegate + * @param provider the provider + * @param algorithm the algorithm + */ + protected KeyGenerator( + KeyGeneratorSpi keyGenSpi, + Provider provider, + String algorithm) + { + this.keyGenerator = keyGenSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns the algorithm name of this <code>KeyGenerator</code> object. + * <p> + * This is the same name that was specified in one of the + * <code>getInstance</code> calls that created this + * <code>KeyGenerator</code> object. + * + * @return the algorithm name of this <code>KeyGenerator</code> object. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Generates a <code>KeyGenerator</code> object for the specified algorithm. + * If the default provider package provides an implementation of the + * requested key generator, an instance of <code>KeyGenerator</code> containing + * that implementation is returned. If the requested key generator is not available + * in the default provider package, other provider packages are searched. + * + * @param algorithm the standard name of the requested key algorithm. See Appendix A in the + * Java Cryptography Extension API Specification & Reference for information about standard + * algorithm names. + * @return the new <code>KeyGenerator</code> object + * @exception NoSuchAlgorithmException if a key generator for the specified algorithm is not + * available in the default provider package or any of the other provider packages that were searched. + */ + public static final KeyGenerator getInstance( + String algorithm) + throws NoSuchAlgorithmException + { + try + { + JCEUtil.Implementation imp = JCEUtil.getImplementation("KeyGenerator", algorithm, (String) null); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + KeyGenerator keyGen = new KeyGenerator((KeyGeneratorSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyGen; + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + /** + * Generates a <code>KeyGenerator</code> object for the specified key + * algorithm from the specified provider. + * + * @param algorithm the standard name of the requested key algorithm. See Appendix A in the + * Java Cryptography Extension API Specification & Reference for information about standard + * algorithm names. + * @param provider the provider + * @return the new <code>KeyGenerator</code> object + * @exception NoSuchAlgorithmException if a key generator for the specified algorithm is not + * available from the specified provider. + */ + public static final KeyGenerator getInstance( + String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to KeyGenerator.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("KeyGenerator", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + KeyGenerator keyGen = new KeyGenerator((KeyGeneratorSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyGen; + } + + /** + * Generates a <code>KeyGenerator</code> object for the specified key + * algorithm from the specified provider. + * + * @param algorithm the standard name of the requested key algorithm. See Appendix A in the + * Java Cryptography Extension API Specification & Reference for information about standard + * algorithm names. + * @param provider the name of the provider + * @return the new <code>KeyGenerator</code> object + * @exception NoSuchAlgorithmException if a key generator for the specified algorithm is not + * available from the specified provider. + * @exception NoSuchProviderException if the specified provider has not been configured. + */ + public static final KeyGenerator getInstance( + String algorithm, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to KeyGenerator.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("KeyGenerator", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + KeyGenerator keyGen = new KeyGenerator((KeyGeneratorSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyGen; + } + + /** + * Returns the provider of this <code>KeyGenerator</code> object. + * + * @return the provider of this <code>KeyGenerator</code> object + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Initializes this key generator. + * + * @param random the source of randomness for this generator + */ + public final void init( + SecureRandom random) + { + keyGenerator.engineInit(random); + } + + /** + * Initializes this key generator with the specified parameter set. + * <p> + * If this key generator requires any random bytes, 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.) + * + * @param params the key generation parameters + * @exception InvalidAlgorithmParameterException if the given parameters are inappropriate + * for this key generator + */ + public final void init( + AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + keyGenerator.engineInit(params, new SecureRandom()); + } + + /** + * Initializes this key generator with the specified parameter set and a user-provided source of randomness. + * + * @param params the key generation parameters + * @param random the source of randomness for this key generator + * @exception InvalidAlgorithmParameterException if <code>params</code> is inappropriate for this key generator + */ + public final void init( + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + keyGenerator.engineInit(params, random); + } + + /** + * Initializes this key generator for a certain keysize. + * <p> + * If this key generator requires any random bytes, 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.) + * + * @param keysize the keysize. This is an algorithm-specific metric, specified in number of bits. + * @exception InvalidParameterException if the keysize is wrong or not supported. + */ + public final void init( + int keysize) + { + keyGenerator.engineInit(keysize, new SecureRandom()); + } + + /** + * Initializes this key generator for a certain keysize, using a user-provided source of randomness. + * + * @param keysize the keysize. This is an algorithm-specific metric, specified in number of bits. + * @param random the source of randomness for this key generator + * @exception InvalidParameterException if the keysize is wrong or not supported. + */ + public final void init( + int keysize, + SecureRandom random) + { + keyGenerator.engineInit(keysize, random); + } + + /** + * Generates a secret key. + * + * @return the new key + */ + public final SecretKey generateKey() + { + return keyGenerator.engineGenerateKey(); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java new file mode 100644 index 000000000..dc7ad3da1 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java @@ -0,0 +1,64 @@ +package javax.crypto; + +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.InvalidParameterException; +import java.security.InvalidAlgorithmParameterException; + +/** + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) + * for the <code>KeyGenerator</code> class. + * All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation + * of a key generator for a particular algorithm. + * + * @see SecretKey + */ +public abstract class KeyGeneratorSpi +{ + public KeyGeneratorSpi() + { + } + + /** + * Initializes the key generator. + * + * @param random the source of randomness for this generator + */ + protected abstract void engineInit( + SecureRandom random); + + /** + * Initializes the key generator with the specified parameter + * set and a user-provided source of randomness. + * + * @param params the key generation parameters + * @param random the source of randomness for this key generator + * @exception InvalidAlgorithmParameterException if <code>params</code> is + * inappropriate for this key generator + */ + protected abstract void engineInit( + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException; + + /** + * Initializes this key generator for a certain keysize, using the given + * source of randomness. + * + * @param keysize the keysize. This is an algorithm-specific metric, specified in number of bits. + * @param random the source of randomness for this key generator. + * @exception InvalidParameterException if keysize is wrong or not supported. + */ + protected abstract void engineInit( + int keysize, + SecureRandom random) + throws InvalidParameterException; + + /** + * Generates a secret key. + * + * @return the new key. + */ + protected abstract SecretKey engineGenerateKey(); +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/Mac.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/Mac.java new file mode 100644 index 000000000..9f6174d82 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/Mac.java @@ -0,0 +1,443 @@ +package javax.crypto; + +import java.security.Provider; +import java.security.Key; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.InvalidAlgorithmParameterException; + +/** + * This class provides the functionality of a "Message Authentication Code" + * (MAC) algorithm. + * <p> + * A MAC provides a way to check the integrity of information transmitted over + * or stored in an unreliable medium, based on a secret key. Typically, message + * authentication codes are used between two parties that share a secret + * key in order to validate information transmitted between these + * parties. + * <p> + * A MAC mechanism that is based on cryptographic hash functions is + * referred to as HMAC. HMAC can be used with any cryptographic hash function, + * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is + * specified in RFC 2104. + */ +public class Mac + implements Cloneable +{ + MacSpi macSpi; + Provider provider; + String algorithm; + + private boolean initialised = false; + + /** + * Creates a MAC object. + * + * @param macSpi the delegate + * @param provider the provider + * @param algorithm the algorithm + */ + protected Mac( + MacSpi macSpi, + Provider provider, + String algorithm) + { + this.macSpi = macSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns the algorithm name of this <code>Mac</code> object. + * <p> + * This is the same name that was specified in one of the + * <code>getInstance</code> calls that created this <code>Mac</code> object. + * + * @return the algorithm name of this <code>Mac</code> object. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Generates an <code>Mac</code> object that implements the + * specified MAC algorithm. + * If the default provider package provides an implementation of the + * requested MAC algorithm, an instance of + * <code>Mac</code> containing that implementation is returned. + * If the algorithm is not available in the default provider package, + * other provider packages are searched. + * + * @param algorithm the standard name of the requested MAC algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @return the new <code>Mac</code> object. + * @exception NoSuchAlgorithmException if the specified algorithm is not + * available in the default provider package or any of the other provider + * packages that were searched. + */ + public static final Mac getInstance( + String algorithm) + throws NoSuchAlgorithmException + { + try + { + JCEUtil.Implementation imp = JCEUtil.getImplementation("Mac", algorithm, (String) null); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + Mac mac = new Mac((MacSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return mac; + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + /** + * Generates an <code>Mac</code> object for the specified MAC + * algorithm from the specified provider. + * + * @param algorithm the standard name of the requested MAC algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @param provider the name of the provider. + * @return the new <code>Mac</code> object. + * @exception NoSuchAlgorithmException if the specified algorithm is not available from the + * specified provider. + * @exception NoSuchProviderException if the specified provider has not been configured. + */ + public static final Mac getInstance( + String algorithm, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to Mac.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("Mac", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + Mac mac = new Mac((MacSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return mac; + } + + /** + * Generates an <code>Mac</code> object for the specified MAC + * algorithm from the specified provider. + * + * @param algorithm the standard name of the requested MAC algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @param provider the provider. + * @return the new <code>Mac</code> object. + * @exception NoSuchAlgorithmException if the specified algorithm is not available from the + * specified provider. + */ + public static final Mac getInstance( + String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to Mac.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("Mac", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + Mac mac = new Mac((MacSpi)imp.getEngine(), imp.getProvider(), algorithm); + + return mac; + } + + /** + * Returns the provider of this <code>Mac</code> object. + * + * @return the provider of this <code>Mac</code> object. + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the length of the MAC in bytes. + * + * @return the MAC length in bytes. + */ + public final int getMacLength() + { + return macSpi.engineGetMacLength(); + } + + /** + * Initializes this <code>Mac</code> object with the given key. + * + * @param key the key. + * @exception InvalidKeyException if the given key is inappropriate for initializing this MAC. + */ + public final void init( + Key key) + throws InvalidKeyException + { + try + { + macSpi.engineInit(key, null); + initialised = true; + } + catch (InvalidAlgorithmParameterException e) + { + throw new IllegalArgumentException("underlying mac waon't work without an AlgorithmParameterSpec"); + } + } + + /** + * Initializes this <code>Mac</code> object with the given key and + * algorithm parameters. + * + * @param key the key. + * @param params the algorithm parameters. + * @exception InvalidKeyException if the given key is inappropriate for initializing this MAC. + * @exception InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate + * for this MAC. + */ + public final void init( + Key key, + AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + macSpi.engineInit(key, params); + initialised = true; + } + + /** + * Processes the given byte. + * + * @param input the input byte to be processed. + * @exception IllegalStateException if this <code>Mac</code> has not been initialized. + */ + public final void update( + byte input) + throws IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("MAC not initialised"); + } + + macSpi.engineUpdate(input); + } + + /** + * Processes the given array of bytes. + * + * @param input the array of bytes to be processed. + * @exception IllegalStateException if this <code>Mac</code> has not been initialized. + */ + public final void update( + byte[] input) + throws IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("MAC not initialised"); + } + + if (input == null) + { + return; + } + + macSpi.engineUpdate(input, 0, input.length); + } + + /** + * Processes the first <code>len</code> bytes in <code>input</code>, + * starting at <code>offset</code> inclusive. + * + * @param input the input buffer. + * @param offset the offset in <code>input</code> where the input starts. + * @param len the number of bytes to process. + * @exception IllegalStateException if this <code>Mac</code> has not been initialized. + */ + public final void update( + byte[] input, + int offset, + int len) + throws IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("MAC not initialised"); + } + + if (input == null) + { + throw new IllegalArgumentException("Null input passed"); + } + + if (len < 0 || offset < 0 || len > (input.length - offset)) + { + throw new IllegalArgumentException("Bad offset/len"); + } + + if (input.length == 0) + { + return; + } + + macSpi.engineUpdate(input, offset, len); + } + + /** + * Finishes the MAC operation. + * <p> + * A call to this method resets this <code>Mac</code> object to the + * state it was in when previously initialized via a call to <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. + * That is, the object is reset and available to generate another MAC from + * the same key, if desired, via new calls to <code>update</code> and + * <code>doFinal</code>. + * (In order to reuse this <code>Mac</code> object with a different key, + * it must be reinitialized via a call to <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. + * + * @return the MAC result. + * @exception IllegalStateException if this <code>Mac</code> has not been initialized. + */ + public final byte[] doFinal() + throws IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("MAC not initialised"); + } + + return macSpi.engineDoFinal(); + } + + /** + * Finishes the MAC operation. + * + * <p>A call to this method resets this <code>Mac</code> object to the + * state it was in when previously initialized via a call to + * <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. + * That is, the object is reset and available to generate another MAC from + * the same key, if desired, via new calls to <code>update</code> and + * <code>doFinal</code>. + * (In order to reuse this <code>Mac</code> object with a different key, + * it must be reinitialized via a call to <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. + * <p> + * The MAC result is stored in <code>output</code>, starting at + * <code>outOffset</code> inclusive. + * + * @param output the buffer where the MAC result is stored + * @param outOffset the offset in <code>output</code> where the MAC is stored + * @exception ShortBufferException if the given output buffer is too small to hold the result + * @exception IllegalStateException if this <code>Mac</code> has not been initialized. + */ + public final void doFinal( + byte[] output, + int outOffset) + throws ShortBufferException, IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("MAC not initialised"); + } + + if ((output.length - outOffset) < macSpi.engineGetMacLength()) + { + throw new ShortBufferException("buffer to short for MAC output"); + } + + byte[] mac = macSpi.engineDoFinal(); + + System.arraycopy(mac, 0, output, outOffset, mac.length); + } + + /** + * Processes the given array of bytes and finishes the MAC operation. + * <p> + * A call to this method resets this <code>Mac</code> object to the + * state it was in when previously initialized via a call to <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. That is, the object is reset and + * available to generate another MAC from the same key, if desired, via new calls to + * <code>update</code> and <code>doFinal</code>. + * (In order to reuse this <code>Mac</code> object with a different key, + * it must be reinitialized via a call to <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. + * + * @return the MAC result. + * @exception IllegalStateException if this <code>Mac</code> has not been initialized. + */ + public final byte[] doFinal( + byte[] input) + throws IllegalStateException + { + if (!initialised) + { + throw new IllegalStateException("MAC not initialised"); + } + + macSpi.engineUpdate(input, 0, input.length); + + return macSpi.engineDoFinal(); + } + + /** + * Resets this <code>Mac</code> object. + * <p> + * A call to this method resets this <code>Mac</code> object to the + * state it was in when previously initialized via a call to + * <code>init(Key)</code> or <code>init(Key, AlgorithmParameterSpec)</code>. + * That is, the object is reset and available to generate another MAC from + * the same key, if desired, via new calls to <code>update</code> and + * <code>doFinal</code>. + * (In order to reuse this <code>Mac</code> object with a different key, + * it must be reinitialized via a call to <code>init(Key)</code> or + * <code>init(Key, AlgorithmParameterSpec)</code>. + */ + public final void reset() + { + macSpi.engineReset(); + } + + /** + * Returns a clone if the provider implementation is cloneable. + * + * @return a clone if the provider implementation is cloneable. + * @exception CloneNotSupportedException if this is called on a delegate that does + * not support <code>Cloneable</code>. + */ + public final Object clone() + throws CloneNotSupportedException + { + Mac result = new Mac((MacSpi)macSpi.clone(), provider, algorithm); + result.initialised = initialised; + return result; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/MacSpi.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/MacSpi.java new file mode 100644 index 000000000..d618ee536 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/MacSpi.java @@ -0,0 +1,92 @@ +package javax.crypto; + +import java.security.Key; +import java.security.InvalidKeyException; +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) + * for the <code>Mac</code> class. + * All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation + * of a particular MAC algorithm. + * <p> + * Implementations are free to implement the Cloneable interface. + */ +public abstract class MacSpi +{ + public MacSpi() + { + } + + /** + * Returns the length of the MAC in bytes. + * + * @return the MAC length in bytes. + */ + protected abstract int engineGetMacLength(); + + /** + * Initializes the MAC with the given (secret) key and algorithm + * parameters. + * + * @param key - the (secret) key. + * @param params - the algorithm parameters. + * @exception InvalidKeyException if the given key is inappropriate for initializing this MAC. + * @exception InvalidAlgorithmParameterException - if the given algorithm parameters are inappropriate + * for this MAC. + */ + protected abstract void engineInit( + Key key, + AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException; + + /** + * Processes the given byte. + * + * @param input - the input byte to be processed. + */ + protected abstract void engineUpdate( + byte input); + + /** + * Processes the first <code>len</code> bytes in <code>input</code>, + * starting at <code>offset</code> inclusive. + * + * @param input the input buffer. + * @param offset the offset in <code>input</code> where the input starts. + * @param len the number of bytes to process. + */ + protected abstract void engineUpdate( + byte[] input, + int offset, + int len); + + /** + * Completes the MAC computation and resets the MAC for further use, + * maintaining the secret key that the MAC was initialized with. + * + * @return the MAC result. + */ + protected abstract byte[] engineDoFinal(); + + /** + * Resets the MAC for further use, maintaining the secret key that the + * MAC was initialized with. + */ + protected abstract void engineReset(); + + /** + * Returns a clone if the implementation is cloneable. + * + * @return a clone if the implementation is cloneable. + * @exception CloneNotSupportedException if this is called on an implementation that does not support + * <code>Cloneable</code>. + */ + public Object clone() + throws CloneNotSupportedException + { + throw new CloneNotSupportedException("Underlying MAC does not support cloning"); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/NoSuchPaddingException.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/NoSuchPaddingException.java new file mode 100644 index 000000000..621732aa3 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/NoSuchPaddingException.java @@ -0,0 +1,36 @@ +package javax.crypto; + +import java.security.GeneralSecurityException; + +/** + * This exception is thrown when a particular padding mechanism is + * requested but is not available in the environment. + */ +public class NoSuchPaddingException + extends GeneralSecurityException +{ + private static final long serialVersionUID = -4572885201200175466L; + + /** + * Constructs a NoSuchPaddingException with no detail + * message. A detail message is a String that describes this + * particular exception. + */ + public NoSuchPaddingException() + { + } + + /** + * Constructs a NoSuchPaddingException with the specified + * detail message. A detail message is a String that describes + * this particular exception, which may, for example, specify which + * algorithm is not available. + * + * @param msg - the detail message. + */ + public NoSuchPaddingException( + String msg) + { + super(msg); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/NullCipher.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/NullCipher.java new file mode 100644 index 000000000..bb1ac7560 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/NullCipher.java @@ -0,0 +1,240 @@ +package javax.crypto; + +import java.security.Key; +import java.security.SecureRandom; +import java.security.InvalidKeyException; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The NullCipher class is a class that provides an + * "identity cipher" -- one that does not tranform the plaintext. As + * a consequence, the ciphertext is identical to the plaintext. All + * initialization methods do nothing, while the blocksize is set to 1 + * byte. + * + * @since JCE1.2 + */ +public class NullCipher + extends Cipher +{ + static private class NullCipherSpi + extends CipherSpi + { + /** + * Sets the mode of this cipher - no op. + */ + protected void engineSetMode( + String mode) + throws NoSuchAlgorithmException + { + } + + /** + * Sets the padding mechanism of this cipher - no op. + */ + protected void engineSetPadding( + String padding) + throws NoSuchPaddingException + { + } + + /** + * Returns the block size (in bytes) - 1 + */ + protected int engineGetBlockSize() + { + return 1; + } + + /** + * 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). + * + * @param inputLen the input length (in bytes) + * @return the required output buffer size (in bytes) + */ + protected int engineGetOutputSize( + int inputLen) + { + return inputLen; + } + + /** + * Returns the initialization vector (IV) in a new buffer. + * + * @return null + */ + protected byte[] engineGetIV() + { + return null; + } + + /** + * Returns the parameters used with this cipher - null + */ + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + /** + * Initializes this cipher with a key and a source + * of randomness - no op. + */ + protected void engineInit( + int opmode, + Key key, + SecureRandom random) + throws InvalidKeyException + { + } + + /** + * Initializes this cipher with a key, a set of + * algorithm parameters, and a source of randomness - no op. + */ + protected void engineInit( + int opmode, + Key key, + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + } + + /** + * Initializes this cipher with a key, a set of + * algorithm parameters, and a source of randomness - no op. + */ + protected void engineInit( + int opmode, + Key key, + AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + } + + /** + * Continues a multiple-part encryption or decryption operation + * (depending on how this cipher was initialized), processing another data + * part - in this case just return a copy of the input. + */ + protected byte[] engineUpdate( + byte[] input, + int inputOffset, + int inputLen) + { + if (input == null) + { + return null; + } + + byte[] tmp = new byte[inputLen]; + + System.arraycopy(input, inputOffset, tmp, 0, inputLen); + + return tmp; + } + + /** + * Continues a multiple-part encryption or decryption operation + * (depending on how this cipher was initialized), processing another data + * part - in this case just copy the input to the output. + */ + protected int engineUpdate( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + throws ShortBufferException + { + if (input == null) + { + return 0; + } + + if ((output.length - outputOffset) < inputLen) + { + throw new ShortBufferException("output buffer to short for NullCipher"); + } + + System.arraycopy(input, inputOffset, output, outputOffset, inputLen); + + return 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 + * - in this case just return a copy of the input. + */ + protected byte[] engineDoFinal( + byte[] input, + int inputOffset, + int inputLen) + throws IllegalBlockSizeException, BadPaddingException + { + if (input == null) + { + return new byte[0]; + } + + byte[] tmp = new byte[inputLen]; + + System.arraycopy(input, inputOffset, tmp, 0, inputLen); + + return tmp; + } + + /** + * 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. + */ + protected int engineDoFinal( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException + { + if (input == null) + { + return 0; + } + + if ((output.length - outputOffset) < inputLen) + { + throw new ShortBufferException("output buffer too short for NullCipher"); + } + + System.arraycopy(input, inputOffset, output, outputOffset, inputLen); + + return inputLen; + } + + /** + * Returns the key size of the given key object - 0 + */ + protected int engineGetKeySize( + Key key) + throws InvalidKeyException + { + return 0; + } + } + + public NullCipher() + { + super(new NullCipherSpi(), null, "NULL"); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/SealedObject.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/SealedObject.java new file mode 100644 index 000000000..576c03bd3 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/SealedObject.java @@ -0,0 +1,302 @@ +package javax.crypto; + +import java.io.*; +import java.security.*; + +/** + * This class enables a programmer to create an object and protect its + * confidentiality with a cryptographic algorithm. + * + * <p> + * Given any Serializable object, one can create a SealedObject + * that encapsulates the original object, in serialized + * format (i.e., a "deep copy"), and seals (encrypts) its serialized contents, + * using a cryptographic algorithm such as DES, to protect its + * confidentiality. The encrypted content can later be decrypted (with + * the corresponding algorithm using the correct decryption key) and + * de-serialized, yielding the original object. + * + * <p> + * Note that the Cipher object must be fully initialized with the + * correct algorithm, key, padding scheme, etc., before being applied + * to a SealedObject. + * + * <p> + * The original object that was sealed can be recovered in two different + * ways: + * <p> + * + * <ul> + * + * <li>by using the <a href="#getObject(javax.crypto.Cipher)">getObject</a> + * method that takes a <code>Cipher</code> object. + * + * <p> + * This method requires a fully initialized <code>Cipher</code> object, + * initialized with the + * exact same algorithm, key, padding scheme, etc., that were used to seal the + * object. + * + * <p> + * This approach has the advantage that the party who unseals the + * sealed object does not require knowledge of the decryption key. For example, + * after one party has initialized the cipher object with the required + * decryption key, it could hand over the cipher object to + * another party who then unseals the sealed object. + * + * <p> + * + * <li>by using one of the + * <a href="#getObject(java.security.Key)">getObject</a> methods + * that take a <code>Key</code> object. + * + * <p> In this approach, the <code>getObject</code> method creates a cipher + * object for the appropriate decryption algorithm and initializes it with the + * given decryption key and the algorithm parameters (if any) that were stored + * in the sealed object. + * + * <p> This approach has the advantage that the party who + * unseals the object does not need to keep track of the parameters (e.g., an + * IV) that were used to seal the object. + * + * </ul> + * + * @see Cipher + */ +public class SealedObject + implements Serializable +{ + private static final long serialVersionUID = 4482838265551344752L; + + private byte[] encodedParams; + private byte[] encryptedContent; + private String paramsAlg; + private String sealAlg; + + /** + * Constructs a SealedObject from any Serializable object. + * <p> + * The given object is serialized, and its serialized contents are + * encrypted using the given Cipher, which must be fully initialized. + * <p> + * Any algorithm parameters that may be used in the encryption + * operation are stored inside of the new <code>SealedObject</code>. + * + * @param object the object to be sealed. + * @param c the cipher used to seal the object. + * @exception IOException if an error occurs during serialization + * @exception IllegalBlockSizeException if the given cipher is a block + * cipher, no padding has been requested, and the total input length + * (i.e., the length of the serialized object contents) is not a multiple + * of the cipher's block size + */ + public SealedObject( + Serializable object, + Cipher c) + throws IOException, IllegalBlockSizeException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + oOut.writeObject(object); + oOut.close(); + byte[] encodedObject = bOut.toByteArray(); + + if (c == null) + { + throw new IllegalArgumentException("cipher object is null!"); + } + + try + { + this.encryptedContent = c.doFinal(encodedObject); + } + catch (BadPaddingException e) + { + // should not happen + throw new IOException(e.getMessage()); + } + + this.sealAlg = c.getAlgorithm(); + AlgorithmParameters params = c.getParameters(); + if (params != null) + { + this.encodedParams = params.getEncoded(); + this.paramsAlg = params.getAlgorithm(); + } + } + + /** + * Returns the algorithm that was used to seal this object. + * + * @return the algorithm that was used to seal this object. + */ + public final String getAlgorithm() + { + return sealAlg; + } + + /** + * Retrieves the original (encapsulated) object. + * <p> + * This method creates a cipher for the algorithm that had been used in + * the sealing operation. + * If the default provider package provides an implementation of that + * algorithm, an instance of Cipher containing that implementation is used. + * If the algorithm is not available in the default package, other + * packages are searched. + * The Cipher object is initialized for decryption, using the given + * <code>key</code> and the parameters (if any) that had been used in the + * sealing operation. + * <p> + * The encapsulated object is unsealed and de-serialized, before it is + * returned. + * + * @param key the key used to unseal the object. + * @return the original object. + * @exception IOException if an error occurs during de-serialiazation. + * @exception ClassNotFoundException if an error occurs during de-serialiazation. + * @exception NoSuchAlgorithmException if the algorithm to unseal the object is not available. + * @exception InvalidKeyException if the given key cannot be used to unseal + * the object (e.g., it has the wrong algorithm). + */ + public final Object getObject( + Key key) + throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeyException + { + if (key == null) + { + throw new IllegalArgumentException("key object is null!"); + } + + try + { + return getObject(key, null); + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(e.getMessage()); + } + } + + /** + * Retrieves the original (encapsulated) object. + * <p> + * The encapsulated object is unsealed (using the given Cipher, + * assuming that the Cipher is already properly initialized) and + * de-serialized, before it is returned. + * + * @param c the cipher used to unseal the object + * @return the original object. + * @exception IOException if an error occurs during de-serialiazation + * @exception ClassNotFoundException if an error occurs during de-serialiazation + * @exception IllegalBlockSizeException if the given cipher is a block + * cipher, no padding has been requested, and the total input length is + * not a multiple of the cipher's block size + * @exception BadPaddingException if the given cipher has been + * initialized for decryption, and padding has been specified, but + * the input data does not have proper expected padding bytes + */ + public final Object getObject( + Cipher c) + throws IOException, ClassNotFoundException, IllegalBlockSizeException, BadPaddingException + { + if (c == null) + { + throw new IllegalArgumentException("cipher object is null!"); + } + + byte[] encodedObject = c.doFinal(encryptedContent); + ObjectInputStream oIn = new ObjectInputStream( + new ByteArrayInputStream(encodedObject)); + return oIn.readObject(); + } + + /** + * Retrieves the original (encapsulated) object. + * <p> + * This method creates a cipher for the algorithm that had been used in + * the sealing operation, using an implementation of that algorithm from + * the given <code>provider</code>. + * The Cipher object is initialized for decryption, using the given + * <code>key</code> and the parameters (if any) that had been used in the + * sealing operation. + * <p> + * The encapsulated object is unsealed and de-serialized, before it is + * returned. + * + * @param key the key used to unseal the object. + * @param provider the name of the provider of the algorithm to unseal + * the object. + * @return the original object. + * @exception IOException if an error occurs during de-serialiazation. + * @exception ClassNotFoundException if an error occurs during + * de-serialization. + * @exception NoSuchAlgorithmException if the algorithm to unseal the + * object is not available. + * @exception NoSuchProviderException if the given provider is not + * configured. + * @exception InvalidKeyException if the given key cannot be used to unseal + * the object (e.g., it has the wrong algorithm). + */ + public final Object getObject( + Key key, + String provider) + throws IOException, ClassNotFoundException, + NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException + { + if (key == null) + { + throw new IllegalArgumentException("key object is null!"); + } + + Cipher cipher = null; + try + { + if (provider != null) + { + cipher = Cipher.getInstance(sealAlg, provider); + } + else + { + cipher = Cipher.getInstance(sealAlg); + } + } + catch (NoSuchPaddingException e) + { + throw new NoSuchAlgorithmException(e.getMessage()); + } + + if (paramsAlg == null) + { + cipher.init(Cipher.DECRYPT_MODE, key); + } + else + { + AlgorithmParameters algParams = + AlgorithmParameters.getInstance(paramsAlg); + algParams.init(encodedParams); + + try + { + cipher.init(Cipher.DECRYPT_MODE, key, algParams); + } + catch (InvalidAlgorithmParameterException e) + { + throw new IOException(e.getMessage()); + } + } + + try + { + return getObject(cipher); + } + catch (BadPaddingException e) + { + throw new IOException(e.getMessage()); + } + catch (IllegalBlockSizeException e2) + { + throw new IOException(e2.getMessage()); + } + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKey.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKey.java new file mode 100644 index 000000000..8b22f02af --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKey.java @@ -0,0 +1,28 @@ +package javax.crypto; + +import java.security.Key; + +/** + * A secret (symmetric) key. + * <p> + * This interface contains no methods or constants. + * Its only purpose is to group (and provide type safety for) secret keys. + * <p> + * Provider implementations of this interface must overwrite the + * <code>equals</code> and <code>hashCode</code> methods inherited from + * <code>java.lang.Object</code>, so that secret keys are compared based on + * their underlying key material and not based on reference. + * <p> + * Keys that implement this interface return the string <code>RAW</code> + * as their encoding format (see <code>getFormat</code>), and return the + * raw key bytes as the result of a <code>getEncoded</code> method call. (The + * <code>getFormat</code> and <code>getEncoded</code> methods are inherited + * from the <code>java.security.Key</code> parent interface.) + * + * @see SecretKeyFactory + * @see Cipher + */ +public abstract interface SecretKey + extends Key +{ +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKeyFactory.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKeyFactory.java new file mode 100644 index 000000000..286f0b5f4 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKeyFactory.java @@ -0,0 +1,245 @@ +package javax.crypto; + +import java.security.Provider; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.spec.KeySpec; +import java.security.spec.InvalidKeySpecException; + +/** + * This class represents a factory for secret keys. + * + * <p> + * Key factories are used to convert <I>keys</I> (opaque + * cryptographic keys of type <code>Key</code>) into <I>key specifications</I> + * (transparent representations of the underlying key material), and vice versa. + * Secret key factories operate only on secret (symmetric) keys. + * <p> + * Key factories are bi-directional, i.e., they allow to build an opaque + * key object from a given key specification (key material), or to retrieve + * the underlying key material of a key object in a suitable format. + * <p> + * Application developers should refer to their provider's documentation + * to find out which key specifications are supported by the + * <a href="#generateSecret(java.security.spec.KeySpec)">generateSecret</a> and + * <a href="#getKeySpec(javax.crypto.SecretKey, java.lang.Class)">getKeySpec</a> methods. + * For example, the DES secret-key factory supplied by the "SunJCE" provider + * supports <code>DESKeySpec</code> as a transparent representation of DES + * keys, and that provider's secret-key factory for Triple DES keys supports + * <code>DESedeKeySpec</code> as a transparent representation of Triple DES keys. + * + * @see SecretKey + * @see javax.crypto.spec.DESKeySpec + * @see javax.crypto.spec.DESedeKeySpec + * @see javax.crypto.spec.PBEKeySpec + */ +public class SecretKeyFactory +{ + SecretKeyFactorySpi keyFacSpi; + Provider provider; + String algorithm; + + /** + * Creates a SecretKeyFactory object. + * + * @param keyFacSpi the delegate + * @param provider the provider + * @param algorithm the secret-key algorithm + */ + protected SecretKeyFactory( + SecretKeyFactorySpi keyFacSpi, + Provider provider, + String algorithm) + { + this.keyFacSpi = keyFacSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Generates a <code>SecretKeyFactory</code> object for the specified secret-key algorithm. + * If the default provider package provides an implementation of the + * requested factory, an instance of <code>SecretKeyFactory</code> + * containing that implementation is returned. + * If the requested factory is not available in the default provider + * package, other provider packages are searched. + * + * @param algorithm the standard name of the requested secret-key algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference </a> + * for information about standard algorithm names. + * @return a <code>SecretKeyFactory</code> object for the specified secret-key algorithm. + * @exception NoSuchAlgorithmException if a secret-key factory for the specified algorithm + * is not available in the default provider package or any of the other provider packages + * that were searched. + */ + public static final SecretKeyFactory getInstance( + String algorithm) + throws NoSuchAlgorithmException + { + try + { + JCEUtil.Implementation imp = JCEUtil.getImplementation("SecretKeyFactory", algorithm, (String) null); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + SecretKeyFactory keyFact = new SecretKeyFactory( + (SecretKeyFactorySpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyFact; + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + /** + * Generates a <code>SecretKeyFactory</code> object for the specified + * secret-key algorithm from the specified provider. + * + * @param algorithm the standard name of the requested secret-key algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @param provider the name of the provider. + * @return a <code>SecretKeyFactory</code> object for the specified secret-key algorithm. + * @exception NoSuchAlgorithmException if a secret-key factory for the specified algorithm is not + * available from the specified provider. + * @exception NoSuchProviderException if the specified provider has not been configured. + */ + public static final SecretKeyFactory getInstance( + String algorithm, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to SecretKeyFactory.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("SecretKeyFactory", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + SecretKeyFactory keyFact = new SecretKeyFactory( + (SecretKeyFactorySpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyFact; + } + + /** + * Generates a <code>SecretKeyFactory</code> object for the specified + * secret-key algorithm from the specified provider. + * + * @param algorithm the standard name of the requested secret-key algorithm. + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + * @param provider the provider. + * @return a <code>SecretKeyFactory</code> object for the specified secret-key algorithm. + * @exception NoSuchAlgorithmException if a secret-key factory for the specified algorithm is not + * available from the specified provider. + */ + public static final SecretKeyFactory getInstance( + String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if (provider == null) + { + throw new IllegalArgumentException("No provider specified to SecretKeyFactory.getInstance()"); + } + + JCEUtil.Implementation imp = JCEUtil.getImplementation("SecretKeyFactory", algorithm, provider); + + if (imp == null) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + + SecretKeyFactory keyFact = new SecretKeyFactory( + (SecretKeyFactorySpi)imp.getEngine(), imp.getProvider(), algorithm); + + return keyFact; + } + + /** + * Returns the provider of this <code>SecretKeyFactory</code> object. + * + * @return the provider of this <code>SecretKeyFactory</code> object + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the algorithm name of this <code>SecretKeyFactory</code> object. + * <p> + * This is the same name that was specified in one of the <code>getInstance</code> calls + * that created this <code>SecretKeyFactory</code> object. + * + * @return the algorithm name of this <code>SecretKeyFactory</code> object. + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Generates a <code>SecretKey</code> object from the provided key specification (key material). + * + * @param keySpec the specification (key material) of the secret key + * @return the secret key + * @exception InvalidKeySpecException if the given key specification + * is inappropriate for this secret-key factory to produce a secret key. + */ + public final SecretKey generateSecret( + KeySpec keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGenerateSecret(keySpec); + } + + /** + * Returns a specification (key material) of the given key object + * in the requested format. + * + * @param key the key + * @param keySpec the requested format in which the key material shall be + * returned + * @return the underlying key specification (key material) in the requested format + * @exception InvalidKeySpecException if the requested key specification is inappropriate for + * the given key (e.g., the algorithms associated with <code>key</code> and <code>keySpec</code> do + * not match, or <code>key</code> references a key on a cryptographic hardware device whereas + * <code>keySpec</code> is the specification of a software-based key), or the given key cannot be dealt with + * (e.g., the given key has an algorithm or format not supported by this secret-key factory). + */ + public final KeySpec getKeySpec( + SecretKey key, + Class keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGetKeySpec(key, keySpec); + } + + /** + * Translates a key object, whose provider may be unknown or potentially + * untrusted, into a corresponding key object of this secret-key factory. + * + * @param key the key whose provider is unknown or untrusted + * @return the translated key + * @exception InvalidKeyException if the given key cannot be processed by this secret-key factory. + */ + public final SecretKey translateKey( + SecretKey key) + throws InvalidKeyException + { + return keyFacSpi.engineTranslateKey(key); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java new file mode 100644 index 000000000..b430f3bd3 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java @@ -0,0 +1,72 @@ +package javax.crypto; + +import java.security.InvalidKeyException; +import java.security.spec.KeySpec; +import java.security.spec.InvalidKeySpecException; + +/** + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) + * for the <code>SecretKeyFactory</code> class. + * All the abstract methods in this class must be implemented by each + * cryptographic service provider who wishes to supply the implementation + * of a secret-key factory for a particular algorithm. + * <p> + * A provider should document all the key specifications supported by its + * secret key factory. + * For example, the DES secret-key factory supplied by the "SunJCE" provider + * supports <code>DESKeySpec</code> as a transparent representation of DES + * keys, and that provider's secret-key factory for Triple DES keys supports + * <code>DESedeKeySpec</code> as a transparent representation of Triple DES + * keys. + * + * @see SecretKey + * @see javax.crypto.spec.DESKeySpec + * @see javax.crypto.spec.DESedeKeySpec + */ +public abstract class SecretKeyFactorySpi +{ + public SecretKeyFactorySpi() + { + } + + /** + * Generates a <code>SecretKey</code> object from the + * provided key specification (key material). + * + * @param keySpec the specification (key material) of the secret key + * @return the secret key + * @exception InvalidKeySpecException if the given key specification + * is inappropriate for this secret-key factory to produce a secret key. + */ + protected abstract SecretKey engineGenerateSecret( + KeySpec keySpec) + throws InvalidKeySpecException; + + /** + * Returns a specification (key material) of the given key object in the requested format. + * + * @param key the key + * @param keySpec the requested format in which the key material shall be returned + * @return the underlying key specification (key material) in the requested format + * @exception InvalidKeySpecException if the requested key specification is inappropriate for + * the given key (e.g., the algorithms associated with <code>key</code> and <code>keySpec</code> do + * not match, or <code>key</code> references a key on a cryptographic hardware device whereas + * <code>keySpec</code> is the specification of a software-based key), or the given key cannot be + * dealt with (e.g., the given key has an algorithm or format not supported by this secret-key factory). + */ + protected abstract KeySpec engineGetKeySpec( + SecretKey key, + Class keySpec) + throws InvalidKeySpecException; + + /** + * Translates a key object, whose provider may be unknown or potentially untrusted, into a + * corresponding key object of this secret-key factory. + * + * @param key the key whose provider is unknown or untrusted + * @return InvalidKeyException if the given key cannot be processed by this secret-key factory. + */ + protected abstract SecretKey engineTranslateKey( + SecretKey key) + throws InvalidKeyException; +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/ShortBufferException.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/ShortBufferException.java new file mode 100644 index 000000000..273a6cf5c --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/ShortBufferException.java @@ -0,0 +1,36 @@ +package javax.crypto; + +import java.security.GeneralSecurityException; + +/** + * This exception is thrown when an output buffer provided by the user + * is too short to hold the operation result. + */ +public class ShortBufferException + extends GeneralSecurityException +{ + private static final long serialVersionUID = 8427718640832943747L; + + /** + * Constructs a ShortBufferException with no detail + * message. A detail message is a String that describes this + * particular exception. + */ + public ShortBufferException() + { + } + + /** + * Constructs a ShortBufferException with the specified + * detail message. A detail message is a String that describes + * this particular exception, which may, for example, specify which + * algorithm is not available. + * + * @param msg the detail message. + */ + public ShortBufferException( + String msg) + { + super(msg); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHKey.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHKey.java new file mode 100644 index 000000000..5d404110f --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHKey.java @@ -0,0 +1,20 @@ +package javax.crypto.interfaces; + +import javax.crypto.spec.DHParameterSpec; + +/** + * The interface to a Diffie-Hellman key. + * + * @see DHParameterSpec + * @see DHPublicKey + * @see DHPrivateKey + */ +public abstract interface DHKey +{ + /** + * Returns the key parameters. + * + * @return the key parameters + */ + public DHParameterSpec getParams(); +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java new file mode 100644 index 000000000..3fc7de99b --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java @@ -0,0 +1,21 @@ +package javax.crypto.interfaces; + +import java.math.BigInteger; +import java.security.PrivateKey; + +/** + * The interface to a Diffie-Hellman private key. + * + * @see DHKey + * @see DHPublicKey + */ +public abstract interface DHPrivateKey + extends DHKey, PrivateKey +{ + /** + * Returns the private value, <code>x</code>. + * + * @return the private value, <code>x</code> + */ + public BigInteger getX(); +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java new file mode 100644 index 000000000..3d395afa4 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java @@ -0,0 +1,21 @@ +package javax.crypto.interfaces; + +import java.math.BigInteger; +import java.security.PublicKey; + +/** + * The interface to a Diffie-Hellman public key. + * + * @see DHKey + * @see DHPrivateKey + */ +public abstract interface DHPublicKey + extends DHKey, PublicKey +{ + /** + * Returns the public value, <code>y</code>. + * + * @return the public value, <code>y</code> + */ + public BigInteger getY(); +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/PBEKey.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/PBEKey.java new file mode 100644 index 000000000..8d9ab1f67 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/interfaces/PBEKey.java @@ -0,0 +1,41 @@ +package javax.crypto.interfaces; + +import javax.crypto.SecretKey; + +/** + * The interface to a PBE key. + * + * @see PBEKeySpec, SecretKey + */ +public interface PBEKey + extends SecretKey +{ + /** + * Returns the password. + * + * Note: this method should return a copy of the password. It is the + * caller's responsibility to zero out the password information after it is + * no longer needed. + * + * @return the password. + */ + public char[] getPassword(); + + /** + * Returns the salt or null if not specified. + * + * Note: this method should return a copy of the salt. It is the caller's + * responsibility to zero out the salt information after it is no longer + * needed. + * + * @return the salt. + */ + public byte[] getSalt(); + + /** + * Returns the iteration count or 0 if not specified. + * + * @return the iteration count. + */ + public int getIterationCount(); +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DESKeySpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DESKeySpec.java new file mode 100644 index 000000000..8509a5464 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DESKeySpec.java @@ -0,0 +1,194 @@ +package javax.crypto.spec; + +import java.security.InvalidKeyException; +import java.security.spec.KeySpec; + +/** + * This class specifies a DES key. + */ +public class DESKeySpec + implements KeySpec +{ + public static final int DES_KEY_LEN = 8; + + private byte[] keyBytes = new byte[DES_KEY_LEN]; + + /** + * Uses the first 8 bytes in <code>key</code> as the key material for the DES key. + * <p> + * The bytes that constitute the DES key are those between + * <code>key[0]</code> and <code>key[7]</code> inclusive. + * + * @param key - the buffer with the DES key material. + * @exception InvalidKeyException - if the given key material is shorter than 8 bytes. + */ + public DESKeySpec( + byte[] key) + throws InvalidKeyException + { + if (key.length < DES_KEY_LEN) + { + throw new InvalidKeyException("DES key material too short in construction"); + } + + System.arraycopy(key, 0, keyBytes, 0, keyBytes.length); + } + + /** + * Uses the first 8 bytes in <code>key</code>, beginning at + * <code>offset</code> inclusive, as the key material for the DES key. + * <p> + * The bytes that constitute the DES key are those between + * <code>key[offset]</code> and <code>key[offset+7]</code> inclusive. + * + * @param key the buffer with the DES key material. + * @param offset the offset in <code>key</code>, where the DES key material starts. + * @exception InvalidKeyException if the given key material, starting at + * <code>offset</code> inclusive, is shorter than 8 bytes. + */ + public DESKeySpec( + byte[] key, + int offset) + throws InvalidKeyException + { + if ((key.length - offset) < DES_KEY_LEN) + { + throw new InvalidKeyException("DES key material too short in construction"); + } + + System.arraycopy(key, offset, keyBytes, 0, keyBytes.length); + } + + /** + * Returns the DES key material. + * + * @return the DES key material. + */ + public byte[] getKey() + { + byte[] tmp = new byte[DES_KEY_LEN]; + + System.arraycopy(keyBytes, 0, tmp, 0, tmp.length); + + return tmp; + } + + /** + * Checks if the given DES key material, starting at <code>offset</code> + * inclusive, is parity-adjusted. + * + * @param key the buffer with the DES key material. + * @param offset the offset in <code>key</code>, where the DES key material starts. + * @returns true if the given DES key material is parity-adjusted, false otherwise. + * @exception InvalidKeyException if the given key material, starting at <code>offset</code> + * inclusive, is shorter than 8 bytes. + */ + public static boolean isParityAdjusted( + byte[] key, + int offset) + throws InvalidKeyException + { + if ((key.length - offset) < DES_KEY_LEN) + { + throw new InvalidKeyException("key material too short in DESKeySpec.isParityAdjusted"); + } + + for (int i = 0; i < DES_KEY_LEN; i++) + { + byte keyByte = key[i + offset]; + int count = 0; + + keyByte = (byte)((keyByte & 0xff) >> 1); + + while (keyByte != 0) + { + /* + * we increment for every "on" bit + */ + if ((keyByte & 0x01) != 0) + { + count++; + } + + keyByte = (byte)((keyByte & 0xff) >> 1); + } + + if ((count & 1) == 1) + { + if ((key[i + offset] & 1) == 1) + { + return false; + } + } + else if ((key[i + offset] & 1) != 1) + { + return false; + } + } + + return true; + } + + /* + * Table of weak and semi-weak keys taken from Schneier pp281 + */ + static private final int N_DES_WEAK_KEYS = 16; + + static private byte[] DES_weak_keys = + { + /* weak keys */ + (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, + (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e, + (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1, + (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, + + /* semi-weak keys */ + (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, + (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1, + (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1, + (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe, + (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e, + (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe, + (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, + (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e, + (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01, + (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e, + (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01, + (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1 + }; + + /** + * Checks if the given DES key material is weak or semi-weak. + * + * @param key the buffer with the DES key material. + * @param offset the offset in <code>key</code>, where the DES key + * material starts. + * @return true if the given DES key material is weak or semi-weak, false otherwise. + * @exception InvalidKeyException if the given key material, starting at <code>offset</code> + * inclusive, is shorter than 8 bytes. + */ + public static boolean isWeak( + byte[] key, + int offset) + throws InvalidKeyException + { + if (key.length - offset < DES_KEY_LEN) + { + throw new InvalidKeyException("key material too short in DESKeySpec.isWeak"); + } + + nextkey: for (int i = 0; i < N_DES_WEAK_KEYS; i++) + { + for (int j = 0; j < DES_KEY_LEN; j++) + { + if (key[j + offset] != DES_weak_keys[i * DES_KEY_LEN + j]) + { + continue nextkey; + } + } + + return true; + } + return false; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java new file mode 100644 index 000000000..edfcd3c43 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java @@ -0,0 +1,100 @@ +package javax.crypto.spec; + +import java.security.InvalidKeyException; +import java.security.spec.KeySpec; + +/** + * This class specifies a DES-EDE ("triple-DES") key. + */ +public class DESedeKeySpec + implements KeySpec +{ + public static final int DES_EDE_KEY_LEN = 24; + + private byte[] keyBytes = new byte[DES_EDE_KEY_LEN]; + + /** + * Uses the first 24 bytes in <code>key</code> as the DES-EDE key. + * <p> + * The bytes that constitute the DES-EDE key are those between + * <code>key[0]</code> and <code>key[23]</code> inclusive + * + * @param key the buffer with the DES-EDE key material. + * @exception InvalidKeyException if the given key material is shorter + * than 24 bytes. + */ + public DESedeKeySpec( + byte[] key) + throws InvalidKeyException + { + if (key.length < DES_EDE_KEY_LEN) + { + throw new InvalidKeyException("DESede key material too short in construction"); + } + + System.arraycopy(key, 0, keyBytes, 0, keyBytes.length); + } + + /** + * Uses the first 24 bytes in <code>key</code>, beginning at + * <code>offset</code> inclusive, as the DES-EDE key. + * <p> + * The bytes that constitute the DES-EDE key are those between + * <code>key[offset]</code> and <code>key[offset+23]</code> inclusive. + * @param key the buffer with the DES-EDE key material. + * @param offset the offset in <code>key</code>, where the DES-EDE key + * material starts. + * @exception InvalidKeyException if the given key material, starting at + * <code>offset</code> inclusive, is shorter than 24 bytes + */ + public DESedeKeySpec( + byte[] key, + int offset) + throws InvalidKeyException + { + if ((key.length - offset) < DES_EDE_KEY_LEN) + { + throw new InvalidKeyException("DESede key material too short in construction"); + } + + System.arraycopy(key, 0, keyBytes, 0, keyBytes.length); + } + + /** + * Returns the DES-EDE key. + * + * @return the DES-EDE key + */ + public byte[] getKey() + { + byte[] tmp = new byte[DES_EDE_KEY_LEN]; + + System.arraycopy(keyBytes, 0, tmp, 0, tmp.length); + + return tmp; + } + + /** + * Checks if the given DES-EDE key, starting at <code>offset</code> + * inclusive, is parity-adjusted. + * + * @return true if the given DES-EDE key is parity-adjusted, false + * otherwise + * @exception InvalidKeyException if the given key material, starting at + * <code>offset</code> inclusive, is shorter than 24 bytes + */ + public static boolean isParityAdjusted( + byte[] key, + int offset) + throws InvalidKeyException + { + if ((key.length - offset) < DES_EDE_KEY_LEN) + { + throw new InvalidKeyException("key material too short in DESedeKeySpec.isParityAdjusted"); + } + + return (DESKeySpec.isParityAdjusted(key, offset) + && DESKeySpec.isParityAdjusted(key, offset + 8) + && DESKeySpec.isParityAdjusted(key, offset + 16)); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java new file mode 100644 index 000000000..56645d135 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java @@ -0,0 +1,56 @@ +package javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the set of parameters used for generating + * Diffie-Hellman (system) parameters for use in Diffie-Hellman key + * agreement. This is typically done by a central + * authority. + * <p> + * The central authority, after computing the parameters, must send this + * information to the parties looking to agree on a secret key. + */ +public class DHGenParameterSpec + implements AlgorithmParameterSpec +{ + private int primeSize; + private int exponentSize; + + /** + * Constructs a parameter set for the generation of Diffie-Hellman + * (system) parameters. The constructed parameter set can be used to + * initialize an <a href="http://java.sun.com/products/jdk/1.2/docs/api/java.security.AlgorithmParameterGenerator.html"><code>AlgorithmParameterGenerator</code></a> + * object for the generation of Diffie-Hellman parameters. + * + * @param primeSize the size (in bits) of the prime modulus. + * @param exponentSize the size (in bits) of the random exponent. + */ + public DHGenParameterSpec( + int primeSize, + int exponentSize) + { + this.primeSize = primeSize; + this.exponentSize = exponentSize; + } + + /** + * Returns the size in bits of the prime modulus. + * + * @return the size in bits of the prime modulus + */ + public int getPrimeSize() + { + return primeSize; + } + + /** + * Returns the size in bits of the random exponent (private value). + * + * @return the size in bits of the random exponent (private value) + */ + public int getExponentSize() + { + return exponentSize; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java new file mode 100644 index 000000000..2eceba4ce --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java @@ -0,0 +1,95 @@ +package javax.crypto.spec; + +import java.math.BigInteger; +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the set of parameters used with the Diffie-Hellman + * algorithm, as specified in PKCS #3: <i>Diffie-Hellman Key-Agreement + * Standard</i>. + * <p> + * A central authority generates parameters and gives them to the two + * entities seeking to generate a secret key. The parameters are a prime + * <code>p</code>, a base <code>g</code>, and optionally the length + * in bits of the private value, <code>l</code>. + * <p> + * It is possible that more than one instance of parameters may be + * generated by a given central authority, and that there may be more than + * one central authority. Indeed, each individual may be its own central + * authority, with different entities having different parameters. + * + * @see javax.crypto.KeyAgreement + */ +public class DHParameterSpec + implements AlgorithmParameterSpec +{ + private BigInteger p; + private BigInteger g; + private int l; + + /** + * Constructs a parameter set for Diffie-Hellman, using a prime modulus + * <code>p</code> and a base generator <code>g</code>. + * + * @param p the prime modulus + * @param g the base generator + */ + public DHParameterSpec( + BigInteger p, + BigInteger g) + { + this.p = p; + this.g = g; + } + + /** + * Constructs a parameter set for Diffie-Hellman, using a prime modulus + * <code>p</code>, a base generator <code>g</code>, and the size in bits, + * <code>l</code>, of the random exponent (private value). + * + * @param p the prime modulus + * @param g the base generator + * @param l the size in bits of the random exponent (private value) + */ + public DHParameterSpec( + BigInteger p, + BigInteger g, + int l) + { + this.p = p; + this.g = g; + this.l = l; + } + + /** + * Returns the prime modulus <code>p</code>. + * + * @return the prime modulus <code>p</code> + */ + public BigInteger getP() + { + return p; + } + + /** + * Returns the base generator <code>g</code>. + * + * @return the base generator <code>g</code> + */ + public BigInteger getG() + { + return g; + } + + /** + * Returns the size in bits, <code>l</code>, of the random exponent + * (private value). + * + * @return the size in bits, <code>l</code>, of the random exponent + * (private value), or 0 if this size has not been set + */ + public int getL() + { + return l; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java new file mode 100644 index 000000000..79fa62281 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java @@ -0,0 +1,61 @@ +package javax.crypto.spec; + +import java.math.BigInteger; +import java.security.spec.KeySpec; + +/** + * This class specifies a Diffie-Hellman private key with its associated parameters. + * + * @see DHPublicKeySpec + */ +public class DHPrivateKeySpec + implements KeySpec +{ + private BigInteger x; + private BigInteger p; + private BigInteger g; + + /** + * Constructor that takes a private value <code>x</code>, a prime + * modulus <code>p</code>, and a base generator <code>g</code>. + */ + public DHPrivateKeySpec( + BigInteger x, + BigInteger p, + BigInteger g) + { + this.x = x; + this.p = p; + this.g = g; + } + + /** + * Returns the private value <code>x</code>. + * + * @return the private value <code>x</code> + */ + public BigInteger getX() + { + return x; + } + + /** + * Returns the prime modulus <code>p</code>. + * + * @return the prime modulus <code>p</code> + */ + public BigInteger getP() + { + return p; + } + + /** + * Returns the base generator <code>g</code>. + * + * @return the base generator <code>g</code> + */ + public BigInteger getG() + { + return g; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java new file mode 100644 index 000000000..1e610d154 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java @@ -0,0 +1,61 @@ +package javax.crypto.spec; + +import java.math.BigInteger; +import java.security.spec.KeySpec; + +/** + * This class specifies a Diffie-Hellman public key with its associated parameters. + * + * @see DHPrivateKeySpec + */ +public class DHPublicKeySpec + implements KeySpec +{ + private BigInteger y; + private BigInteger p; + private BigInteger g; + + /** + * Constructor that takes a public value <code>y</code>, a prime + * modulus <code>p</code>, and a base generator <code>g</code>. + */ + public DHPublicKeySpec( + BigInteger y, + BigInteger p, + BigInteger g) + { + this.y = y; + this.p = p; + this.g = g; + } + + /** + * Returns the public value <code>y</code>. + * + * @return the public value <code>y</code> + */ + public BigInteger getY() + { + return y; + } + + /** + * Returns the prime modulus <code>p</code>. + * + * @return the prime modulus <code>p</code> + */ + public BigInteger getP() + { + return p; + } + + /** + * Returns the base generator <code>g</code>. + * + * @return the base generator <code>g</code> + */ + public BigInteger getG() + { + return g; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java new file mode 100644 index 000000000..4ed7376c0 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java @@ -0,0 +1,75 @@ +package javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies an <i>initialization vector</i> (IV). IVs are used + * by ciphers in feedback mode, e.g., DES in CBC mode. + */ +public class IvParameterSpec + implements AlgorithmParameterSpec +{ + private byte[] iv; + + /** + * Uses the bytes in <code>iv</code> as the IV. + * + * @param iv the buffer with the IV + */ + public IvParameterSpec( + byte[] iv) + { + if (iv == null) + { + throw new IllegalArgumentException("null iv passed"); + } + + this.iv = new byte[iv.length]; + + System.arraycopy(iv, 0, this.iv, 0, iv.length); + } + + /** + * Uses the first <code>len</code> bytes in <code>iv</code>, + * beginning at <code>offset</code> inclusive, as the IV. + * <p> + * The bytes that constitute the IV are those between + * <code>iv[offset]</code> and <code>iv[offset+len-1]</code> inclusive. + * + * @param iv the buffer with the IV + * @param offset the offset in <code>iv</code> where the IV starts + * @param len the number of IV bytes + */ + public IvParameterSpec( + byte[] iv, + int offset, + int len) + { + if (iv == null) + { + throw new IllegalArgumentException("Null iv passed"); + } + + if (offset < 0 || len < 0 || (iv.length - offset) < len) + { + throw new IllegalArgumentException("Bad offset/len"); + } + + this.iv = new byte[len]; + + System.arraycopy(iv, offset, this.iv, 0, len); + } + + /** + * Returns the initialization vector (IV). + * + * @return the initialization vector (IV) + */ + public byte[] getIV() + { + byte[] tmp = new byte[iv.length]; + + System.arraycopy(iv, 0, tmp, 0, iv.length); + return tmp; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java new file mode 100644 index 000000000..ccc5ad86e --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java @@ -0,0 +1,103 @@ +package javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the set of parameters used with OAEP Padding, as defined + * in the PKCS #1 standard. Its ASN.1 definition in PKCS#1 standard is described + * below: + * + * </pre> + * + * RSAES-OAEP-params ::= SEQUENCE { hashAlgorithm [0] OAEP-PSSDigestAlgorithms + * DEFAULT sha1, maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1, + * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty } + * + * </pre> + * + * where + * + * <pre> + * + * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= { { OID id-sha1 PARAMETERS + * NULL }| { OID id-sha256 PARAMETERS NULL }| { OID id-sha384 PARAMETERS NULL } | { + * OID id-sha512 PARAMETERS NULL }, ... -- Allows for future expansion -- } + * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { { OID id-mgf1 PARAMETERS + * OAEP-PSSDigestAlgorithms }, ... -- Allows for future expansion -- } + * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= { { OID id-pSpecified + * PARAMETERS OCTET STRING }, ... -- Allows for future expansion -- } + * + * </pre> + * + * @see PSource + */ +public class OAEPParameterSpec + implements AlgorithmParameterSpec +{ + private String mdName; + private String mgfName; + private AlgorithmParameterSpec mgfSpec; + private PSource pSrc; + + /** + * Constructs a parameter set for OAEP padding as defined in the PKCS #1 + * standard using the specified message digest algorithm mdName, mask + * generation function algorithm mgfName, parameters for the mask generation + * function mgfSpec, and source of the encoding input P pSrc. + * + * @param mdName the algorithm name for the message digest. + * @param mgfName the algorithm name for the mask generation function. + * @param mgfSpec the parameters for the mask generation function. If null is + * specified, null will be returned by getMGFParameters(). + * @param pSrc the source of the encoding input P. + * @throws NullPointerException if mdName, mgfName, or pSrc is null. + */ + public OAEPParameterSpec(String mdName, String mgfName, + AlgorithmParameterSpec mgfSpec, PSource pSrc) + { + this.mdName = mdName; + this.mgfName = mgfName; + this.mgfSpec = mgfSpec; + this.pSrc = pSrc; + } + + /** + * Returns the message digest algorithm name. + * + * @return the message digest algorithm name. + */ + public String getDigestAlgorithm() + { + return mdName; + } + + /** + * Returns the mask generation function algorithm name. + * + * @return the mask generation function algorithm name. + */ + public String getMGFAlgorithm() + { + return mgfName; + } + + /** + * Returns the parameters for the mask generation function. + * + * @return the parameters for the mask generation function. + */ + public AlgorithmParameterSpec getMGFParameters() + { + return mgfSpec; + } + + /** + * Returns the source of encoding input P. + * + * @return the source of encoding input P. + */ + public PSource getPSource() + { + return pSrc; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java new file mode 100644 index 000000000..3727031bc --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java @@ -0,0 +1,222 @@ +package javax.crypto.spec; + +import java.security.spec.KeySpec; + +import javax.crypto.SecretKeyFactory; + +/** + * A user-chosen password that can be used with password-based encryption (PBE). + * <p> + * The password can be viewed as some kind of raw key material, from which the + * encryption mechanism that uses it derives a cryptographic key. + * <p> + * Different PBE mechanisms may consume different bits of each password + * character. For example, the PBE mechanism defined in PKCS #5 looks at only + * the low order 8 bits of each character, whereas PKCS #12 looks at all 16 bits + * of each character. + * <p> + * You convert the password characters to a PBE key by creating an instance of + * the appropriate secret-key factory. For example, a secret-key factory for + * PKCS #5 will construct a PBE key from only the low order 8 bits of each + * password character, whereas a secret-key factory for PKCS #12 will take all + * 16 bits of each character. + * <p> + * Also note that this class stores passwords as char arrays instead of String + * objects (which would seem more logical), because the String class is + * immutable and there is no way to overwrite its internal value when the + * password stored in it is no longer needed. Hence, this class requests the + * password as a char array, so it can be overwritten when done. + * + * @see SecretKeyFactory + * @see PBEParameterSpec + */ +public class PBEKeySpec + implements KeySpec +{ + + private char[] password; + + private byte[] salt; + + private int iterationCount; + + private int keyLength; + + private boolean isPasswordCleared; + + /** + * Constructor that takes a password. An empty char[] is used if null is + * specified. + * <p> + * Note: password is cloned before it is stored in the new PBEKeySpec + * object. + * + * @param password - + * the password. + */ + public PBEKeySpec(char[] password) + { + if (password == null) + { + this.password = new char[0]; + } + else + { + this.password = new char[password.length]; + + System.arraycopy(password, 0, this.password, 0, password.length); + } + } + + /** + * Returns a copy of the password. + * <p> + * Note: this method returns a copy of the password. It is the caller's + * responsibility to zero out the password information after it is no longer + * needed. + * + * @return the password + * @throws IllegalStateException - + * if password has been cleared by calling clearPassword method. + */ + public final char[] getPassword() + { + if (isPasswordCleared) + { + throw new IllegalStateException("Password has been cleared"); + } + return password; + } + + /** + * Constructor that takes a password, salt, iteration count, and + * to-be-derived key length for generating PBEKey of variable-key-size PBE + * ciphers. An empty char[] is used if null is specified for password. + * <p> + * Note: the password and salt are cloned before they are stored in the new + * PBEKeySpec object. + * + * + * @param password + * password - the password. + * @param salt + * salt - the salt. + * @param iterationCount + * iterationCount - the iteration count. + * @param keyLength + * keyLength - the to-be-derived key length. + * @throws NullPointerException - + * if salt is null. + * @throws IllegalArgumentException - + * if salt is empty, i.e. 0-length, iterationCount or keyLength + * is not positive. + */ + public PBEKeySpec(char[] password, byte[] salt, int iterationCount, int keyLength) + { + this(password); + if (salt == null) + { + throw new NullPointerException("salt is null"); + } + if (salt.length == 0) + { + throw new IllegalArgumentException("salt is empty"); + } + if (iterationCount < 0) + { + throw new IllegalArgumentException("iterationCount is not positive"); + } + if (keyLength < 0) + { + throw new IllegalArgumentException("keyLength is not positive"); + } + this.keyLength = keyLength; + this.iterationCount = iterationCount; + this.salt = (byte[]) salt.clone(); + } + + /** + * Constructor that takes a password, salt, iteration count for generating + * PBEKey of fixed-key-size PBE ciphers. An empty char[] is used if null is + * specified for password. + * <p> + * Note: the password and salt are cloned before they are stored in the new + * PBEKeySpec object. + * + * @param password - + * the password. + * @param salt - + * the salt. + * @param iterationCount - + * the iteration count. + * @throws NullPointerException - + * if salt is null. + * @throws IllegalArgumentException - + * if salt is empty, i.e. 0-length, or iterationCount is not + * positive. + */ + public PBEKeySpec(char[] password, byte[] salt, int iterationCount) + { + this(password, salt, iterationCount, 0); + } + + /** + * Clears the internal copy of the password. + */ + public final void clearPassword() + { + for (int i = 0; i < password.length; i++) + { + password[i] = 0; + } + password = null; + isPasswordCleared = true; + } + + /** + * Returns a copy of the salt or null if not specified. + * + * Note: this method should return a copy of the salt. It is the caller's + * responsibility to zero out the salt information after it is no longer + * needed. + * + * @return the salt. + */ + public final byte[] getSalt() + { + if (salt != null) + { + byte[] tmp = new byte[salt.length]; + + System.arraycopy(salt, 0, tmp, 0, salt.length); + + return tmp; + } + + return null; + } + + /** + * Returns the iteration count or 0 if not specified. + * + * @return the iteration count. + */ + public final int getIterationCount() + { + return iterationCount; + } + + /** + * Returns the to-be-derived key length or 0 if not specified. + * <p> + * Note: this is used to indicate the preference on key length for + * variable-key-size ciphers. The actual key size depends on each provider's + * implementation. + * + * @return the to-be-derived key length. + */ + public final int getKeyLength() + { + return keyLength; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java new file mode 100644 index 000000000..2f714ea9e --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java @@ -0,0 +1,55 @@ +package javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the set of parameters used with password-based encryption (PBE), as defined in the + * <a href="http://www.rsa.com/rsalabs/pubs/PKCS/html/pkcs-5.html">PKCS #5</a> standard. + */ +public class PBEParameterSpec + implements AlgorithmParameterSpec +{ + private byte[] salt; + private int iterationCount; + + /** + * Constructs a parameter set for password-based encryption as defined in + * the PKCS #5 standard. + * + * @param salt the salt. + * @param iterationCount the iteration count. + */ + public PBEParameterSpec( + byte[] salt, + int iterationCount) + { + this.salt = new byte[salt.length]; + System.arraycopy(salt, 0, this.salt, 0, salt.length); + + this.iterationCount = iterationCount; + } + + /** + * Returns the salt. + * + * @return the salt + */ + public byte[] getSalt() + { + byte[] tmp = new byte[salt.length]; + + System.arraycopy(salt, 0, tmp, 0, salt.length); + + return tmp; + } + + /** + * Returns the iteration count. + * + * @return the iteration count + */ + public int getIterationCount() + { + return iterationCount; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PSource.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PSource.java new file mode 100644 index 000000000..03016e1f2 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/PSource.java @@ -0,0 +1,98 @@ +package javax.crypto.spec; + +/** + * This class specifies the source for encoding input P in OAEP Padding, as + * defined in the {@link http://www.ietf.org/rfc/rfc3447.txt PKCS #1} standard. + * + * <pre> + * + * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-pSpecified PARAMETERS OCTET STRING }, + * ... -- Allows for future expansion -- + * } + * </pre> + */ +public class PSource +{ + /** + * This class is used to explicitly specify the value for encoding input P + * in OAEP Padding. + * + */ + public final static class PSpecified + extends PSource + { + private byte[] p; + + /** + * The encoding input P whose value equals byte[0]. + */ + public static final PSpecified DEFAULT = new PSpecified(new byte[0]); + + /** + * Constructs the source explicitly with the specified value p as the + * encoding input P. + * + * @param p the value of the encoding input. The contents of the array + * are copied to protect against subsequent modification. + * @throws NullPointerException if p is null. + */ + public PSpecified(byte[] p) + { + super("PSpecified"); + if (p == null) + { + throw new NullPointerException("The encoding input is null"); + } + this.p = copyOf(p); + } + + /** + * Returns the value of encoding input P. + * + * @return the value of encoding input P. A new array is returned each + * time this method is called. + */ + public byte[] getValue() + { + return copyOf(p); + } + + private byte[] copyOf(byte[] b) + { + byte[] tmp = new byte[b.length]; + + System.arraycopy(b, 0, tmp, 0, b.length); + + return tmp; + } + } + + private String pSrcName; + + /** + * Constructs a source of the encoding input P for OAEP padding as defined + * in the PKCS #1 standard using the specified PSource algorithm. + * + * @param pSrcName the algorithm for the source of the encoding input P. + * @throws NullPointerException if pSrcName is null. + */ + protected PSource(String pSrcName) + { + if (pSrcName == null) + { + throw new NullPointerException("pSrcName is null"); + } + this.pSrcName = pSrcName; + } + + /** + * Returns the PSource algorithm name. + * + * @return the PSource algorithm name. + */ + public String getAlgorithm() + { + return pSrcName; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java new file mode 100644 index 000000000..bea52516d --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java @@ -0,0 +1,162 @@ +package javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the parameters used with the + * <a href="http://www.rsa.com/rsalabs/newfaq/q75.html"><i>RC2</i></a> + * algorithm. + * <p> + * The parameters consist of an effective key size and optionally + * an 8-byte initialization vector (IV) (only in feedback mode). + * <p> + * This class can be used to initialize a <code>Cipher</code> object that + * implements the <i>RC2</i> algorithm. + */ +public class RC2ParameterSpec + implements AlgorithmParameterSpec +{ + private int effectiveKeyBits; + private byte[] iv = new byte[8]; + + /** + * Constructs a parameter set for RC2 from the given effective key size + * (in bits). + * + * @param effectiveKeyBits the effective key size in bits. + */ + public RC2ParameterSpec( + int effectiveKeyBits) + { + this.effectiveKeyBits = effectiveKeyBits; + } + + /** + * Constructs a parameter set for RC2 from the given effective key size + * (in bits) and an 8-byte IV. + * <p> + * The bytes that constitute the IV are those between + * <code>iv[0]</code> and <code>iv[7]</code> inclusive. + * + * @param effectiveKeyBits the effective key size in bits. + * @param iv the buffer with the 8-byte IV. + */ + public RC2ParameterSpec( + int effectiveKeyBits, + byte[] iv) + { + this(effectiveKeyBits, iv, 0); + } + + /** + * Constructs a parameter set for RC2 from the given effective key size + * (in bits) and IV. + * <p> + * The IV is taken from <code>iv</code>, starting at + * <code>offset</code> inclusive. + * The bytes that constitute the IV are those between + * <code>iv[offset]</code> and <code>iv[offset+7]</code> inclusive. + * + * @param effectiveKeyBits the effective key size in bits. + * @param iv the buffer with the IV. + * @param offset the offset in <code>iv</code> where the 8-byte IV starts. + */ + public RC2ParameterSpec( + int effectiveKeyBits, + byte[] iv, + int offset) + { + this.effectiveKeyBits = effectiveKeyBits; + + this.iv = new byte[8]; + System.arraycopy(iv, offset, this.iv, 0, this.iv.length); + } + + /** + * Returns the effective key size in bits. + * + * @return the effective key size in bits. + */ + public int getEffectiveKeyBits() + { + return effectiveKeyBits; + } + + /** + * Returns the IV or null if this parameter set does not contain an IV. + * + * @return the IV or null if this parameter set does not contain an IV. + */ + public byte[] getIV() + { + if (iv == null) + { + return null; + } + + byte[] tmp = new byte[iv.length]; + + System.arraycopy(iv, 0, tmp, 0, tmp.length); + + return tmp; + } + + /** + * Tests for equality between the specified object and this + * object. Two RC2ParameterSpec objects are considered equal if their + * effective key sizes and IVs are equal. + * (Two IV references are considered equal if both are <tt>null</tt>.) + * + * @param obj the object to test for equality with this object. + * @return true if the objects are considered equal, false otherwise. + * @override equals in class java.lang.Object + */ + public boolean equals( + Object obj) + { + if ((obj == null) || !(obj instanceof RC2ParameterSpec)) + { + return false; + } + + RC2ParameterSpec spec = (RC2ParameterSpec)obj; + + if (this.effectiveKeyBits != spec.effectiveKeyBits) + { + return false; + } + + if (iv != null) + { + if (spec.iv == null) + { + return false; + } + + for (int i = 0; i != iv.length; i++) + { + if (iv[i] != spec.iv[i]) + { + return false; + } + } + } + else if (spec.iv != null) + { + return false; + } + + return true; + } + + /** + * Calculates a hash code value for the object. + * Objects that are equal will also have the same hashcode. + * + * @override hashCode in class java.lang.Object + */ + public int hashCode() + { + throw new RuntimeException("Not yet implemented"); + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java new file mode 100644 index 000000000..a34c645b4 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java @@ -0,0 +1,224 @@ +package javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the parameters used with the + * <a href="http://www.rsa.com/rsalabs/newfaq/q76.html"><i>RC5</i></a> + * algorithm. + * <p> + * The parameters consist of a version number, a rounds count, a word + * size, and optionally an initialization vector (IV) (only in feedback mode). + * <p> + * This class can be used to initialize a <code>Cipher</code> object that + * implements the <i>RC5</i> algorithm as supplied by + * <a href="http://www.rsa.com">RSA Data Security, Inc.</a> (RSA DSI), + * or any parties authorized by RSA DSI. + */ +public class RC5ParameterSpec + implements AlgorithmParameterSpec +{ + private int version; + private int rounds; + private int wordSize; + + private byte[] iv; + + /** + * Constructs a parameter set for RC5 from the given version, number of + * rounds and word size (in bits). + * + * @param version the version. + * @param rounds the number of rounds. + * @param wordSize the word size in bits. + */ + public RC5ParameterSpec( + int version, + int rounds, + int wordSize) + { + this.version = version; + this.rounds = rounds; + this.wordSize = wordSize; + this.iv = null; + } + + /** + * Constructs a parameter set for RC5 from the given version, number of + * rounds, word size (in bits), and IV. + * <p> + * Note that the size of the IV (block size) must be twice the word + * size. The bytes that constitute the IV are those between + * <code>iv[0]</code> and <code>iv[2*(wordSize/8)-1]</code> inclusive. + * + * @param version the version. + * @param rounds the number of rounds. + * @param wordSize the word size in bits. + * @param iv the buffer with the IV. + */ + public RC5ParameterSpec( + int version, + int rounds, + int wordSize, + byte[] iv) + { + this(version, rounds, wordSize, iv, 0); + } + + /** + * Constructs a parameter set for RC5 from the given version, number of + * rounds, word size (in bits), and IV. + * <p> + * The IV is taken from <code>iv</code>, starting at <code>offset</code> inclusive. + * Note that the size of the IV (block size), starting at + * <code>offset</code> inclusive, must be twice the word size. + * The bytes that constitute the IV are those between + * <code>iv[offset]</code> and <code>iv[offset+2*(wordSize/8)-1]</code> + * inclusive. + * + * @param version the version. + * @param rounds the number of rounds. + * @param wordSize the word size in bits. + * @param iv the buffer with the IV. + * @param offset the offset in <code>iv</code> where the IV starts. + */ + public RC5ParameterSpec( + int version, + int rounds, + int wordSize, + byte[] iv, + int offset) + { + this.version = version; + this.rounds = rounds; + this.wordSize = wordSize; + this.iv = new byte[2 * (wordSize / 8)]; + + System.arraycopy(iv, offset, this.iv, 0, this.iv.length); + } + + /** + * Returns the version. + * + * @return the version. + */ + public int getVersion() + { + return version; + } + + /** + * Returns the number of rounds. + * + * @return the number of rounds. + */ + public int getRounds() + { + return rounds; + } + + /** + * Returns the word size in bits + * + * @return the word size in bits. + */ + public int getWordSize() + { + return wordSize; + } + + /** + * Returns the IV or null if this parameter set does not contain an IV. + * + * @return the IV or null if this parameter set does not contain an IV. + */ + public byte[] getIV() + { + if (iv == null) + { + return null; + } + + byte[] tmp = new byte[iv.length]; + + System.arraycopy(iv, 0, tmp, 0, iv.length); + + return tmp; + } + + /** + * Tests for equality between the specified object and this + * object. Two RC5ParameterSpec objects are considered equal if their + * version numbers, number of rounds, word sizes, and IVs are equal. + * (Two IV references are considered equal if both are <tt>null</tt>.) + * + * @param obj the object to test for equality with this object. + * @return true if the objects are considered equal, false otherwise. + */ + public boolean equals( + Object obj) + { + if ((obj == null) || !(obj instanceof RC5ParameterSpec)) + { + return false; + } + + RC5ParameterSpec spec = (RC5ParameterSpec)obj; + + if (this.version != spec.version) + { + return false; + } + + if (this.rounds != spec.rounds) + { + return false; + } + + if (this.wordSize != spec.wordSize) + { + return false; + } + + if (iv != null) + { + if (spec.iv == null || spec.iv.length != iv.length) + { + return false; + } + + for (int i = 0; i != iv.length; i++) + { + if (iv[i] != spec.iv[i]) + { + return false; + } + } + } + else if (spec.iv != null) + { + return false; + } + + return true; + } + + /** + * Calculates a hash code value for the object. + * Objects that are equal will also have the same hashcode. + */ + public int hashCode() + { + int code = version ^ rounds ^ wordSize; + + if (iv != null) + { + for (int i = 0; i != iv.length; i++) + { + code ^= iv[i] << (8 * (i % 4)); + } + } + + return code; + } +} diff --git a/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java new file mode 100644 index 000000000..e60be1605 --- /dev/null +++ b/libraries/spongycastle/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java @@ -0,0 +1,193 @@ +package javax.crypto.spec; + +import javax.crypto.SecretKey; +import java.security.spec.KeySpec; + +/** + * This class specifies a secret key in a provider-independent fashion. + * <p> + * It can be used to construct a <code>SecretKey</code> from a byte array, + * without having to go through a (provider-based) + * <code>SecretKeyFactory</code>. + * <p> + * This class is only useful for raw secret keys that can be represented as + * a byte array and have no key parameters associated with them, e.g., DES or + * Triple DES keys. + * + * @see SecretKey + * @see javax.crypto.SecretKeyFactory + */ +public class SecretKeySpec + implements KeySpec, SecretKey +{ + private static final long serialVersionUID = 6577238317307289933L; + + private String algorithm; + private byte[] key; + + /** + * Constructs a secret key from the given byte array. + * <p> + * This constructor does not check if the given bytes indeed specify a + * secret key of the specified algorithm. For example, if the algorithm is + * DES, this constructor does not check if <code>key</code> is 8 bytes + * long, and also does not check for weak or semi-weak keys. + * In order for those checks to be performed, an algorithm-specific + * <i>key specification</i> class (in this case: + * <a href = "DESKeySpec.html"><code>DESKeySpec</code></a>) + * should be used. + * + * @param key the key material of the secret key. + * @param algorithm the name of the secret-key algorithm to be associated + * See Appendix A in the Java Cryptography Extension API Specification & Reference + * for information about standard algorithm names. + */ + public SecretKeySpec( + byte[] key, + String algorithm) + { + if (key == null) + { + throw new IllegalArgumentException("null key passed"); + } + + if (algorithm == null) + { + throw new IllegalArgumentException("null algorithm passed"); + } + + this.key = new byte[key.length]; + System.arraycopy(key, 0, this.key, 0, key.length); + this.algorithm = algorithm; + } + + /** + * Constructs a secret key from the given byte array, using the first + * <code>len</code> bytes of <code>key</code>, starting at + * <code>offset</code> inclusive. + * <p> + * The bytes that constitute the secret key are those between <code>key[offset]</code> and + * <code>key[offset+len-1]</code> inclusive. + * <p> + * This constructor does not check if the given bytes indeed specify a + * secret key of the specified algorithm. For example, if the algorithm is + * DES, this constructor does not check if <code>key</code> is 8 bytes + * long, and also does not check for weak or semi-weak keys. + * In order for those checks to be performed, an algorithm-specific key + * specification class (in this case: <a href = "DESKeySpec.html"><code>DESKeySpec</code></a>) + * must be used. + * + * @param key the key material of the secret key. + * @param offset the offset in <code>key</code> where the key material starts. + * @param len the length of the key material. + * @param algorithm the name of the secret-key algorithm to be associated + * with the given key material. See Appendix A in the Java Cryptography Extension API + * Specification & Reference for information about standard algorithm names. + */ + public SecretKeySpec( + byte[] key, + int offset, + int len, + String algorithm) + { + if (key == null) + { + throw new IllegalArgumentException("Null key passed"); + } + + if ((key.length - offset) < len) + { + throw new IllegalArgumentException("Bad offset/len"); + } + + if (algorithm == null) + { + throw new IllegalArgumentException("Null algorithm string passed"); + } + + this.key = new byte[len]; + System.arraycopy(key, offset, this.key, 0, len); + this.algorithm = algorithm; + } + + /** + * Returns the name of the algorithm associated with this secret key. + * + * @return the secret key algorithm. + */ + public String getAlgorithm() + { + return algorithm; + } + + /** + * Returns the name of the encoding format for this secret key. + * + * @return the string "RAW". + */ + public java.lang.String getFormat() + { + return "RAW"; + } + + /** + * Returns the key material of this secret key. + * + * @return the key material + */ + public byte[] getEncoded() + { + byte[] tmp = new byte[key.length]; + + System.arraycopy(key, 0, tmp, 0, tmp.length); + + return tmp; + } + + /** + * Calculates a hash code value for the object. + * Objects that are equal will also have the same hashcode. + */ + public int hashCode() + { + int code = algorithm.toUpperCase().hashCode(); + + for (int i = 0; i != this.key.length; i++) + { + code ^= this.key[i] << (8 * (i % 4)); + } + + return code; + } + + public boolean equals( + Object obj) + { + if ((obj == null) || !(obj instanceof SecretKeySpec)) + { + return false; + } + + SecretKeySpec spec = (SecretKeySpec)obj; + + if (!this.algorithm.equalsIgnoreCase(spec.algorithm)) + { + return false; + } + + if (this.key.length != spec.key.length) + { + return false; + } + + for (int i = 0; i != this.key.length; i++) + { + if (this.key[i] != spec.key[i]) + { + return false; + } + } + + return true; + } +} |