From 7d834773210d8393785968712873dd3b4074a970 Mon Sep 17 00:00:00 2001
From: free will <2647778488@qq.com>
Date: Wed, 28 Jul 2021 13:15:06 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E4=BA=86spongycastle?=
=?UTF-8?q?=E4=B8=AD=E7=9A=84jce=E6=96=87=E4=BB=B6=E5=A4=B9=EF=BC=8C?=
=?UTF-8?q?=E7=94=A8=E4=BB=A5=E6=9B=BF=E6=8D=A2jce.jar=E5=8C=85=EF=BC=8C?=
=?UTF-8?q?=E4=BD=86=E6=B5=8B=E8=AF=95=E6=9C=AA=E9=80=9A=E8=BF=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README | 9 +
pom.xml | 22 +
src/main/java/SM4/BC_SM4.java | 131 ++
.../javax/crypto/BadPaddingException.java | 37 +
.../src/main/java/javax/crypto/Cipher.java | 1510 +++++++++++++++++
.../java/javax/crypto/CipherInputStream.java | 364 ++++
.../java/javax/crypto/CipherOutputStream.java | 194 +++
.../src/main/java/javax/crypto/CipherSpi.java | 607 +++++++
.../javax/crypto/EncryptedPrivateKeyInfo.java | 236 +++
.../java/javax/crypto/ExemptionMechanism.java | 9 +
.../crypto/ExemptionMechanismException.java | 34 +
.../crypto/IllegalBlockSizeException.java | 36 +
.../src/main/java/javax/crypto/JCEUtil.java | 202 +++
.../main/java/javax/crypto/KeyAgreement.java | 398 +++++
.../java/javax/crypto/KeyAgreementSpi.java | 162 ++
.../main/java/javax/crypto/KeyGenerator.java | 304 ++++
.../java/javax/crypto/KeyGeneratorSpi.java | 65 +
.../jce/src/main/java/javax/crypto/Mac.java | 446 +++++
.../src/main/java/javax/crypto/MacSpi.java | 92 +
.../javax/crypto/NoSuchPaddingException.java | 36 +
.../main/java/javax/crypto/NullCipher.java | 243 +++
.../main/java/javax/crypto/SealedObject.java | 306 ++++
.../src/main/java/javax/crypto/SecretKey.java | 30 +
.../java/javax/crypto/SecretKeyFactory.java | 247 +++
.../javax/crypto/SecretKeyFactorySpi.java | 73 +
.../javax/crypto/ShortBufferException.java | 36 +
.../java/javax/crypto/interfaces/DHKey.java | 22 +
.../javax/crypto/interfaces/DHPrivateKey.java | 23 +
.../javax/crypto/interfaces/DHPublicKey.java | 23 +
.../java/javax/crypto/interfaces/PBEKey.java | 41 +
.../java/javax/crypto/spec/DESKeySpec.java | 194 +++
.../java/javax/crypto/spec/DESedeKeySpec.java | 101 ++
.../javax/crypto/spec/DHGenParameterSpec.java | 56 +
.../javax/crypto/spec/DHParameterSpec.java | 95 ++
.../javax/crypto/spec/DHPrivateKeySpec.java | 62 +
.../javax/crypto/spec/DHPublicKeySpec.java | 62 +
.../javax/crypto/spec/IvParameterSpec.java | 75 +
.../javax/crypto/spec/OAEPParameterSpec.java | 104 ++
.../java/javax/crypto/spec/PBEKeySpec.java | 223 +++
.../javax/crypto/spec/PBEParameterSpec.java | 55 +
.../main/java/javax/crypto/spec/PSource.java | 98 ++
.../javax/crypto/spec/RC2ParameterSpec.java | 162 ++
.../javax/crypto/spec/RC5ParameterSpec.java | 224 +++
.../java/javax/crypto/spec/SecretKeySpec.java | 193 +++
src/test/java/SM4HelperForConnection.java | 61 +
src/test/java/TestSM4.java | 36 +
46 files changed, 7739 insertions(+)
create mode 100644 README
create mode 100644 src/main/java/SM4/BC_SM4.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/BadPaddingException.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/Cipher.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/CipherInputStream.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/CipherOutputStream.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/CipherSpi.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanism.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanismException.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/JCEUtil.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/KeyAgreement.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/KeyAgreementSpi.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/KeyGenerator.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/Mac.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/MacSpi.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/NoSuchPaddingException.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/NullCipher.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/SealedObject.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/SecretKey.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactory.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/ShortBufferException.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/interfaces/DHKey.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/interfaces/PBEKey.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/DESKeySpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/PSource.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java
create mode 100644 src/main/java/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java
create mode 100644 src/test/java/SM4HelperForConnection.java
create mode 100644 src/test/java/TestSM4.java
diff --git a/README b/README
new file mode 100644
index 0000000..987217f
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+本项目试图解决安卓不能正常运行SM4算法的问题。
+jce文件夹下的代码
+ 改编自于:https://github.com/rtyley/spongycastle
+ 用以代替jre下的jce.jar包
+项目测试报错:
+ java.lang.ClassCastException: org.spongycastle.jcajce.provider.symmetric.SM4$ECB cannot be cast to jce.src.main.java.javax.crypto.CipherSpi
+报错原因分析:
+ jce文件夹下代码用到了java.security,在sm4测试代码调用其中的cipher时,传入的参数是符合java.security规范的,
+ 正常情况下可以转为jce.jar包中的cipherspi,但是jce文件夹下的cipherspi被视为特殊类,不能正常做强制类型转换。
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c84fe56..d5e5c96 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,6 +20,28 @@
+ * In order to create a Cipher object, the application calls the
+ * Cipher's getInstance method, and passes the name of the
+ * requested transformation to it. Optionally, the name of a provider
+ * may be specified.
+ *
+ * A transformation 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., DES), and may be followed by a feedback mode and + * padding scheme. + * + *
A transformation is of the form:
+ * + *
+ *
(in the latter case, + * provider-specific default values for the mode and padding scheme are used). + * For example, the following is a valid transformation:
+ * + *
+ * Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
+ *
+ *
+ * When requesting a block cipher in stream cipher mode (e.g.,
+ * DES in CFB or OFB 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 "DES/CFB8/NoPadding" and "DES/OFB32/PKCS5Padding"
+ * 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 Cipher object that implements the specified
+ * transformation.
+ *
+ * If the default provider package supplies an implementation of the
+ * requested transformation, an instance of Cipher 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., DES/CBC/PKCS5Padding.
+ * 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 transformation 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 Cipher object that implements the specified
+ * transformation, as supplied by the specified provider.
+ *
+ * @param transformation the name of the transformation, e.g., DES/CBC/PKCS5Padding.
+ * 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 transformation 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 Cipher object that implements the specified
+ * transformation, as supplied by the specified provider.
+ *
+ * @param transformation the name of the transformation, e.g., DES/CBC/PKCS5Padding.
+ * 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 transformation 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 Cipher object.
+ *
+ * @return the provider of this Cipher object
+ */
+ public final Provider getProvider()
+ {
+ return provider;
+ }
+
+ /**
+ * Returns the algorithm name of this Cipher object.
+ *
+ * This is the same name that was specified in one of the
+ * getInstance calls that created this Cipher
+ * object..
+ *
+ * @return the algorithm name of this Cipher 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 update or
+ * doFinal operation, given the input length inputLen (in bytes).
+ *
+ * This call takes into account any unprocessed (buffered) data from a
+ * previous update call, and padding.
+ *
+ * The actual output length of the next update or
+ * doFinal 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 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.
+ *
+ * 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. + *
+ * 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. + *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters that cannot be
+ * derived from the given key, 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
+ * InvalidKeyException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * getParameters or
+ * getIV (if the parameter is an IV).
+ *
+ * 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
+ * SecureRandom 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.)
+ *
+ * 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:
+ * ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters that cannot be
+ * derived from the given key, 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
+ * InvalidKeyException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ * 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: ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters and
+ * params 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
+ * InvalidAlgorithmParameterException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * getParameters or
+ * getIV (if the parameter is an IV).
+ *
+ * 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
+ *
+ * SecureRandom 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.)
+ *
+ * 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: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE
+ * or UNWRAP_MODE)
+ * @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 params 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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters and
+ * params 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
+ * InvalidAlgorithmParameterException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * getParameters or
+ * getIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ * 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: ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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 params 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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters and
+ * params 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
+ * InvalidAlgorithmParameterException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * getParameters or
+ * getIV (if the parameter is an IV).
+ *
+ * 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
+ *
+ * SecureRandom 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.)
+ *
+ * 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: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE
+ * or UNWRAP_MODE)
+ * @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 params 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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters and
+ * params 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
+ * InvalidAlgorithmParameterException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * getParameters or
+ * getIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ * 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: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE
+ * or UNWRAP_MODE)
+ * @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 params 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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending
+ * on the value of opmode.
+ *
+ * If the certificate is of type X.509 and has a key usage
+ * extension field marked as critical, and the value of the key usage
+ * 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 opmode,
+ * an InvalidKeyException
+ * is thrown.
+ *
+ * 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
+ * InvalidKeyException if it is being initialized for decryption or
+ * key unwrapping.
+ * The generated parameters can be retrieved using
+ * getParameters or
+ * getIV (if the parameter is an IV).
+ *
+ * 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
+ *
+ * SecureRandom
+ * 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.)
+ *
+ * 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:
+ * ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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.
+ *
The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping
+ * or key unwrapping, depending on
+ * the value of opmode.
+ *
+ * If the certificate is of type X.509 and has a key usage
+ * extension field marked as critical, and the value of the key usage
+ * 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
+ * opmode,
+ * an InvalidKeyException
+ * is thrown.
+ *
+ * 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 random values) if it is being
+ * initialized for encryption or key wrapping, and raise an
+ * InvalidKeyException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ * 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: ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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.
+ *
+ * The bytes in the input buffer are processed, and the
+ * result is stored in a new buffer.
+ *
+ * If input has a length of zero, this method returns
+ * null.
+ *
+ * @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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, are processed,
+ * and the result is stored in a new buffer.
+ *
+ * If inputLen is zero, this method returns
+ * null.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input 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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, are processed,
+ * and the result is stored in the output buffer.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * getOutputSize to determine how big
+ * the output buffer should be.
+ *
+ * If inputLen is zero, this method returns
+ * a length of zero.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input where the input starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @return the number of bytes stored in output
+ * @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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, are processed,
+ * and the result is stored in the output buffer, starting at
+ * outputOffset inclusive.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * getOutputSize to determine how big
+ * the output buffer should be.
+ *
+ * If inputLen is zero, this method returns
+ * a length of zero.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input where the input starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in output where the result
+ * is stored
+ * @return the number of bytes stored in output
+ * @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.
+ *
+ * Input data that may have been buffered during a previous
+ * update operation is processed, with padding (if requested)
+ * being applied.
+ * The result is stored in a new buffer.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to init.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * init) 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 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.
+ *
+ * Input data that may have been buffered during a previous
+ * update operation is processed, with padding (if requested)
+ * being applied.
+ * The result is stored in the output buffer, starting at
+ * outputOffset inclusive.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * getOutputSize to determine how big
+ * the output buffer should be.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to init.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * init) more data.
+ *
+ * @param output the buffer for the result
+ * @param outputOffset the offset in output where the result
+ * is stored
+ * @return the number of bytes stored in output
+ * @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.
+ *
+ * The bytes in the input buffer, and any input bytes that
+ * may have been buffered during a previous update operation,
+ * are processed, with padding (if requested) being applied.
+ * The result is stored in a new buffer.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to init.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * init) 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 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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, and any input
+ * bytes that may have been buffered during a previous update
+ * operation, are processed, with padding (if requested) being applied.
+ * The result is stored in a new buffer.
+ *
A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to init.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * init) more data.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input 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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, and any input
+ * bytes that may have been buffered during a previous update
+ * operation, are processed, with padding (if requested) being applied.
+ * The result is stored in the output buffer.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * getOutputSize to determine how big
+ * the output buffer should be.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to init.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * init) more data.
+ * @param input the input buffer
+ * @param inputOffset the offset in input where the input starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @return the number of bytes stored in output
+ * @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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, and any input
+ * bytes that may have been buffered during a previous
+ * update operation, are processed, with padding
+ * (if requested) being applied.
+ * The result is stored in the output buffer, starting at
+ * outputOffset inclusive.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown. In this case, repeat this
+ * call with a larger output buffer. Use
+ * getOutputSize to determine how big
+ * the output buffer should be.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to init.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * init) more data.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input where the input starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in output where the result is
+ * stored
+ * @return the number of bytes stored in output
+ * @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
SECRET_KEY, PRIVATE_KEY, or PUBLIC_KEY.
+ * @return the unwrapped key.
+ * @exception IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized).
+ * @exception InvalidKeyException if wrappedKey does not
+ * represent a wrapped key, or if the algorithm associated with the
+ * wrapped key is different from wrappedKeyAlgorithm
+ * and/or its key type is different from wrappedKeyType.
+ * @exception NoSuchAlgorithmException - if no installed providers
+ * can create keys for the wrappedKeyAlgorithm.
+ */
+ 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/src/main/java/jce/src/main/java/javax/crypto/CipherInputStream.java b/src/main/java/jce/src/main/java/javax/crypto/CipherInputStream.java
new file mode 100644
index 0000000..88bb6a5
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/CipherInputStream.java
@@ -0,0 +1,364 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.Cipher;
+import jce.src.main.java.javax.crypto.CipherOutputStream;
+import jce.src.main.java.javax.crypto.NullCipher;
+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.
+ * + * 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. + *
+ * 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
+ * skip method skips, and the available
+ * method counts only data that have been processed by the encapsulated Cipher.
+ *
+ * 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 javax.crypto.Cipher
+ * @see CipherOutputStream
+ */
+public class CipherInputStream
+ extends FilterInputStream
+{
+ private jce.src.main.java.javax.crypto.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 int in the range
+ * 0 to 255. If no byte is available
+ * because the end of the stream has been reached, the value
+ * -1 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 -1 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 b.length bytes of data from this input
+ * stream into an array of bytes.
+ *
+ * The read method of InputStream calls
+ * the read method of three arguments with the arguments
+ * b, 0, and b.length.
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * -1 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 len 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 null, up to
+ * len 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 -1
+ * 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 n bytes of input from the bytes that can be read
+ * from this input stream without blocking.
+ *
+ * Fewer bytes than requested might be skipped.
+ * The actual number of bytes skipped is equal to n or
+ * the result of a call to available,
+ * whichever is smaller.
+ * If n is less than zero, no bytes are skipped.
+ *
+ * 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 available method of
+ * InputStream returns 0. This method
+ * should 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.
+ *
+ * The close method of CipherInputStream
+ * calls the close method of its underlying input
+ * stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since JCE1.2
+ */
+ public void close()
+ throws IOException
+ {
+ if (!finalized)
+ {
+ finalized = true;
+ try
+ {
+ c.doFinal();
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error processing stream: " + e.toString());
+ }
+ }
+ super.close();
+ }
+
+ /**
+ * Tests if this input stream supports the mark
+ * and reset methods, which it does not.
+ *
+ * @return false, since this class does not support the
+ * mark and reset methods.
+ * @since JCE1.2
+ * @see #mark(int)
+ * @see #reset()
+ */
+ public boolean markSupported()
+ {
+ return false;
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/CipherOutputStream.java b/src/main/java/jce/src/main/java/javax/crypto/CipherOutputStream.java
new file mode 100644
index 0000000..5628c2b
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/CipherOutputStream.java
@@ -0,0 +1,194 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.Cipher;
+import jce.src.main.java.javax.crypto.CipherInputStream;
+import jce.src.main.java.javax.crypto.NullCipher;
+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.
+ *
+ * For example, if the cipher is initialized for encryption, the + * CipherOutputStream will attempt to encrypt data before writing out the + * encrypted data. + *
+ * 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. + *
+ * 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 jce.src.main.java.javax.crypto.Cipher
+ * @see CipherInputStream
+ */
+public class CipherOutputStream
+ extends FilterOutputStream
+{
+ private jce.src.main.java.javax.crypto.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 byte.
+ * @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 b.length bytes from the specified byte array
+ * to this output stream.
+ *
+ * The write method of
+ * CipherOutputStream calls the write
+ * method of three arguments with the three arguments
+ * b, 0, and b.length.
+ *
+ * @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 len bytes from the specified byte array
+ * starting at offset off 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.
+ *
+ *
+ * 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 write 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.
+ *
+ * This method invokes the doFinal 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
+ * flush method of this output stream.
+ *
+ * This method resets the encapsulated cipher object to its initial state
+ * and calls the close 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/src/main/java/jce/src/main/java/javax/crypto/CipherSpi.java b/src/main/java/jce/src/main/java/javax/crypto/CipherSpi.java
new file mode 100644
index 0000000..2766d74
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/CipherSpi.java
@@ -0,0 +1,607 @@
+package jce.src.main.java.javax.crypto;
+
+import 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 Service Provider Interface (SPI)
+ * for the Cipher 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.
+ *
+ * In order to create an instance of Cipher, which
+ * encapsulates an instance of this CipherSpi class, an
+ * application calls one of the
+ * getInstance
+ * factory methods of the
+ * Cipher engine class and specifies the requested
+ * transformation.
+ * Optionally, the application may also specify the name of a provider.
+ *
+ * A transformation 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., DES), and may be followed by a feedback mode and + * padding scheme. + *
+ * A transformation is of the form: + *
+ *
+ *
(in the latter case, + * provider-specific default values for the mode and padding scheme are used). + * For example, the following is a valid transformation:
+ * + *
+ * Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
+ *
+ *
+ * A provider may supply a separate class for each combination
+ * of algorithm/mode/padding, or may decide to provide more generic
+ * classes representing sub-transformations corresponding to
+ * algorithm or algorithm/mode or algorithm//padding
+ * (note the double slashes),
+ * in which case the requested mode and/or padding are set automatically by
+ * the getInstance methods of Cipher, which invoke
+ * the engineSetMode and
+ * engineSetPadding
+ * methods of the provider's subclass of CipherSpi.
+ *
+ *
A Cipher property in a provider master class may have one of
+ * the following formats:
+ *
+ *
+ * // provider's subclass of "CipherSpi" implements "algName" with
+ * // pluggable mode and padding
+ * Cipher.algName
+ *
+ *
+ *
+ * // provider's subclass of "CipherSpi" implements "algName" in the
+ * // specified "mode", with pluggable padding
+ * Cipher.algName/mode
+ *
+ *
+ *
+ * // provider's subclass of "CipherSpi" implements "algName" with the
+ * // specified "padding", with pluggable mode
+ * Cipher.algName//padding
+ *
+ *
+ *
+ * // provider's subclass of "CipherSpi" implements "algName" with the
+ * // specified "mode" and "padding"
+ * Cipher.algName/mode/padding
+ *
+ *
+ * For example, a provider may supply a subclass of CipherSpi
+ * that implements DES/ECB/PKCS5Padding, one that implements
+ * DES/CBC/PKCS5Padding, one that implements
+ * DES/CFB/PKCS5Padding, and yet another one that implements
+ * DES/OFB/PKCS5Padding. That provider would have the following
+ * Cipher properties in its master class:
+ * + *
+ * Cipher.DES/ECB/PKCS5Padding
+ *
+ *
+ *
+ * Cipher.DES/CBC/PKCS5Padding
+ *
+ *
+ *
+ * Cipher.DES/CFB/PKCS5Padding
+ *
+ *
+ *
+ * Cipher.DES/OFB/PKCS5Padding
+ *
+ *
+ * Another provider may implement a class for each of the above modes
+ * (i.e., one class for ECB, one for CBC, one for CFB,
+ * and one for OFB), one class for PKCS5Padding,
+ * and a generic DES class that subclasses from CipherSpi.
+ * That provider would have the following
+ * Cipher properties in its master class:
+ * + *
+ * Cipher.DES
+ *
+ *
+ * The getInstance factory method of the Cipher
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of CipherSpi for a
+ * transformation of the form "algorithm":
+ *
+ *
CipherSpi
+ * for the specified "algorithm".
+ * If the answer is YES, instantiate this + * class, for whose mode and padding scheme default values (as supplied by + * the provider) are used. + *
If the answer is NO, throw a NoSuchAlgorithmException
+ * exception.
+ *
The getInstance factory method of the Cipher
+ * engine class follows these rules in order to instantiate a provider's
+ * implementation of CipherSpi for a
+ * transformation of the form "algorithm/mode/padding":
+ *
+ *
CipherSpi
+ * for the specified "algorithm/mode/padding" transformation.
+ * If the answer is YES, instantiate it. + *
If the answer is NO, go to the next step.
+ *
CipherSpi
+ * for the sub-transformation "algorithm/mode".
+ * If the answer is YES, instantiate it, and call
+ * engineSetPadding(padding) on the new instance.
+ *
If the answer is NO, go to the next step.
+ *
CipherSpi
+ * for the sub-transformation "algorithm//padding" (note the double
+ * slashes).
+ * If the answer is YES, instantiate it, and call
+ * engineSetMode(mode) on the new instance.
+ *
If the answer is NO, go to the next step.
+ *
CipherSpi
+ * for the sub-transformation "algorithm".
+ * If the answer is YES, instantiate it, and call
+ * engineSetMode(mode) and
+ * engineSetPadding(padding) on the new instance.
+ *
If the answer is NO, throw a NoSuchAlgorithmException
+ * exception.
+ *
update
+ * or doFinal operation, given the input length
+ * inputLen (in bytes).
+ *
+ * This call takes into account any unprocessed (buffered) data from a
+ * previous update call, and padding.
+ *
+ * The actual output length of the next update or
+ * doFinal 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.
+ *
+ * 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. + *
+ * 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. + *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending on
+ * the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters that cannot be
+ * derived from the given key, 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
+ * InvalidKeyException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ *
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:
+ * ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending on
+ * the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters and
+ * params 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
+ * InvalidAlgorithmParameterException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ * 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:
+ * ENCRYPT_MODE, DECRYPT_MODE,
+ * WRAP_MODE or UNWRAP_MODE)
+ * @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 params 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.
+ *
+ * The cipher is initialized for one of the following four operations:
+ * encryption, decryption, key wrapping or key unwrapping, depending on
+ * the value of opmode.
+ *
+ * If this cipher requires any algorithm parameters and
+ * params 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
+ * InvalidAlgorithmParameterException if it is being
+ * initialized for decryption or key unwrapping.
+ * The generated parameters can be retrieved using
+ * engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ *
+ * 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:
+ * ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE
+ * or UNWRAP_MODE)
+ * @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 params 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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, are processed,
+ * and the result is stored in a new buffer.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input 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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, are processed,
+ * and the result is stored in the output buffer, starting at
+ * outputOffset inclusive.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input where the input starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in output where the result is stored
+ * @return the number of bytes stored in output
+ * @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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, and any input
+ * bytes that may have been buffered during a previous update
+ * operation, are processed, with padding (if requested) being applied.
+ * The result is stored in a new buffer.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to engineInit.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * engineInit) more data.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input 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.
+ *
+ * The first inputLen bytes in the input
+ * buffer, starting at inputOffset inclusive, and any input
+ * bytes that may have been buffered during a previous update
+ * operation, are processed, with padding (if requested) being applied.
+ * The result is stored in the output buffer, starting at
+ * outputOffset inclusive.
+ *
+ * If the output buffer is too small to hold the result,
+ * a ShortBufferException is thrown.
+ *
+ * A call to this method resets this cipher object to the state
+ * it was in when previously initialized via a call to
+ * engineInit.
+ * That is, the object is reset and available to encrypt or decrypt
+ * (depending on the operation mode that was specified in the call to
+ * engineInit) more data.
+ *
+ * @param input the input buffer
+ * @param inputOffset the offset in input where the input starts
+ * @param inputLen the input length
+ * @param output the buffer for the result
+ * @param outputOffset the offset in output where the result is stored
+ * @return the number of bytes stored in output
+ * @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.
+ *
+ * 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. + * + *
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 SECRET_KEY,
+ * PRIVATE_KEY, or PUBLIC_KEY.
+ * @return the unwrapped key.
+ * @exception InvalidKeyException if wrappedKey does not represent a wrapped key,
+ * or if the algorithm associated with the wrapped key is different from wrappedKeyAlgorithm
+ * and/or its key type is different from wrappedKeyType.
+ * @exception NoSuchAlgorithmException - if no installed providers can create keys for the
+ * wrappedKeyAlgorithm.
+ */
+ protected 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.
+ *
+ * This concrete method has been added to this previously-defined
+ * abstract class. It throws an UnsupportedOperationException
+ * 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 key is invalid.
+ */
+ protected int engineGetKeySize(
+ Key key)
+ throws InvalidKeyException
+ {
+ throw new UnsupportedOperationException("Key size unavailable");
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java b/src/main/java/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
new file mode 100644
index 0000000..cdaf723
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
@@ -0,0 +1,236 @@
+package jce.src.main.java.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;
+
+import jce.src.main.java.javax.crypto.Cipher;
+
+/**
+ * This class implements the EncryptedPrivateKeyInfo type
+ * as defined in PKCS #8.
+ *
Its ASN.1 definition is as follows: + * + *
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ * encryptionAlgorithm AlgorithmIdentifier,
+ * encryptedData OCTET STRING }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ *
+ */
+public class EncryptedPrivateKeyInfo
+{
+ private org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo infoObj;
+ private AlgorithmParameters algP;
+
+ /*
+ * Constructs (i.e., parses) an EncryptedPrivateKeyInfo from
+ * its ASN.1 encoding.
+ *
+ * @param encoded the ASN.1 encoding of this object.
+ * @exception NullPointerException if the encoded 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 EncryptedPrivateKeyInfo from the
+ * encryption algorithm name and the encrypted data.
+ * Note: the encrypedData is cloned when constructing
+ * this object.
+ *
+ * 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 algName or encryptedData is null.
+ * @exception IllegalArgumentException if encryptedData 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");
+ }
+
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(new DERObjectIdentifier(algName), null);
+
+ infoObj = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, (byte[])encryptedData.clone());
+ algP = this.getParameters();
+ }
+
+ /**
+ * Constructs an EncryptedPrivateKeyInfo from the
+ * encryption algorithm parameters and the encrypted data.
+ *
Note: the encrypedData is cloned when constructing
+ * this object.
+ *
+ * @param algParams the algorithm parameters for the encryption
+ * algorithm. algParams.getEncoded() should return
+ * the ASN.1 encoded bytes of the parameters field
+ * of the AlgorithmIdentifer component of the
+ * EncryptedPrivateKeyInfo type.
+ * @param encryptedData encrypted data.
+ * @exception NullPointerException if algParams or encryptedData is null.
+ * @exception IllegalArgumentException if encryptedData is empty, i.e. 0-length.
+ * @exception NoSuchAlgorithmException if the specified algName of the specified algParams parameter is not supported.
+ */
+ public EncryptedPrivateKeyInfo(
+ AlgorithmParameters algParams,
+ byte[] encryptedData)
+ throws NullPointerException, IllegalArgumentException, NoSuchAlgorithmException
+ {
+ if (algParams == null || encryptedData == null)
+ {
+ throw new NullPointerException("parameters null");
+ }
+
+ 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().getAlgorithm().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/src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanism.java b/src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanism.java
new file mode 100644
index 0000000..1885e90
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanism.java
@@ -0,0 +1,9 @@
+package jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanismException.java b/src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanismException.java
new file mode 100644
index 0000000..52b49fe
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/ExemptionMechanismException.java
@@ -0,0 +1,34 @@
+package jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java b/src/main/java/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java
new file mode 100644
index 0000000..a4927f3
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/IllegalBlockSizeException.java
@@ -0,0 +1,36 @@
+package jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/JCEUtil.java b/src/main/java/jce/src/main/java/javax/crypto/JCEUtil.java
new file mode 100644
index 0000000..d110682
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/JCEUtil.java
@@ -0,0 +1,202 @@
+package jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/KeyAgreement.java b/src/main/java/jce/src/main/java/javax/crypto/KeyAgreement.java
new file mode 100644
index 0000000..d9b2cb4
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/KeyAgreement.java
@@ -0,0 +1,398 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.KeyAgreementSpi;
+import jce.src.main.java.javax.crypto.KeyGenerator;
+import jce.src.main.java.javax.crypto.SecretKey;
+import jce.src.main.java.javax.crypto.ShortBufferException;
+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 (KeyPairGenerator or
+ * KeyGenerator), a KeyFactory, or as a result from
+ * an intermediate phase of the key agreement protocol
+ * (see doPhase).
+ *
+ * For each of the correspondents in the key exchange, doPhase
+ * needs to be called. For example, if this key exchange is with one other
+ * party, doPhase needs to be called once, with the
+ * lastPhase flag set to true.
+ * If this key exchange is
+ * with two other parties, doPhase needs to be called twice,
+ * the first time setting the lastPhase flag to
+ * false, and the second time setting it to true.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * @see KeyGenerator
+ * @see javax.crypto.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 KeyAgreement object.
+ *
+ * This is the same name that was specified in one of the
+ * getInstance calls that created this
+ * KeyAgreement object.
+ *
+ * @return the algorithm name of this KeyAgreement object.
+ */
+ public final String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * Generates a KeyAgreement 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
+ * KeyAgreement 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 KeyAgreement 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 KeyAgreement 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 KeyAgreement 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 KeyAgreement 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 KeyAgreement 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 KeyAgreement object.
+ *
+ * @return the provider of this KeyAgreement 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.
+ *
+ * If this key agreement requires any random bytes, it will get
+ * them using the
+ * SecureRandom 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.
+ *
+ * If the key agreement algorithm requires random bytes, it gets them
+ * from the given source of randomness, random.
+ * However, if the underlying
+ * algorithm implementation does not require any random bytes,
+ * random 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.
+ *
+ * If this key agreement requires any random bytes, it will get
+ * them using the
+ * SecureRandom 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.
+ *
+ * This method resets this KeyAgreement object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the init 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
+ * sharedSecret, beginning at offset inclusive.
+ *
+ * If the sharedSecret buffer is too small to hold the
+ * result, a ShortBufferException is thrown.
+ * In this case, this call should be repeated with a larger output buffer.
+ *
+ * This method resets this KeyAgreement object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the init 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 sharedSecret where the
+ * shared secret will be stored
+ * @return the number of bytes placed into sharedSecret
+ * @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 SecretKey
+ * object of the specified algorithm.
+ *
+ * This method resets this KeyAgreement object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the init 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/src/main/java/jce/src/main/java/javax/crypto/KeyAgreementSpi.java b/src/main/java/jce/src/main/java/javax/crypto/KeyAgreementSpi.java
new file mode 100644
index 0000000..e6b9e6d
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/KeyAgreementSpi.java
@@ -0,0 +1,162 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.KeyGenerator;
+import jce.src.main.java.javax.crypto.SecretKey;
+import jce.src.main.java.javax.crypto.ShortBufferException;
+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 Service Provider Interface (SPI)
+ * for the KeyAgreement 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.
+ *
+ * The keys involved in establishing a shared secret are created by one of the
+ * key generators (KeyPairGenerator or KeyGenerator),
+ * a KeyFactory, or as a result from an intermediate phase of the key
+ * agreement protocol (see engineDoPhase).
+ *
+ * For each of the correspondents in the key exchange, engineDoPhase
+ * needs to be called. For example, if the key exchange is with one other
+ * party, engineDoPhase needs to be called once, with the
+ * lastPhase flag set to true.
+ * If the key exchange is with two other parties, engineDoPhase needs to be called twice,
+ * the first time setting the lastPhase flag to
+ * false, and the second time setting it to true.
+ * There may be any number of parties involved in a key exchange.
+ *
+ * @see KeyGenerator
+ * @see javax.crypto.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.
+ *
+ * If the key agreement algorithm requires random bytes, it gets them
+ * from the given source of randomness, random.
+ * However, if the underlying
+ * algorithm implementation does not require any random bytes,
+ * random 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.
+ *
+ * This method resets this KeyAgreementSpi object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the engineInit 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
+ * sharedSecret, beginning at offset inclusive.
+ *
+ * If the sharedSecret buffer is too small to hold the result,
+ * a ShortBufferException is thrown. In this case, this call should be
+ * repeated with a larger output buffer.
+ *
+ * This method resets this KeyAgreementSpi object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the engineInit 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 sharedSecret where the shared secret will be stored
+ * @return the number of bytes placed into sharedSecret
+ * @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.
+ *
+ * This method resets this KeyAgreementSpi object, so that it
+ * can be reused for further key agreements. Unless this key agreement is
+ * reinitialized with one of the engineInit 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/src/main/java/jce/src/main/java/javax/crypto/KeyGenerator.java b/src/main/java/jce/src/main/java/javax/crypto/KeyGenerator.java
new file mode 100644
index 0000000..504781d
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/KeyGenerator.java
@@ -0,0 +1,304 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.KeyGeneratorSpi;
+import jce.src.main.java.javax.crypto.SecretKey;
+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.
+ *
+ * Key generators are constructed using one of the getInstance
+ * class methods of this class.
+ *
+ * KeyGenerator objects are reusable, i.e., after a key has been + * generated, the same KeyGenerator object can be re-used to generate further + * keys. + *
+ * 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: + * + *
All key generators share the concepts of a keysize and a
+ * source of randomness.
+ * There is an
+ * init
+ * method in this KeyGenerator class that takes these two universally
+ * shared types of arguments. There is also one that takes just a
+ * keysize 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.
+ *
+ * Since no other parameters are specified when you call the above
+ * algorithm-independent init 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.
+ *
+ *
For situations where a set of algorithm-specific parameters already
+ * exists, there are two
+ * init
+ * methods that have an AlgorithmParameterSpec
+ * argument. One also has a SecureRandom 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).
+ *
In case the client does not explicitly initialize the KeyGenerator
+ * (via a call to an init method), each provider must
+ * supply (and document) a default initialization.
+ *
+ * @see javax.crypto.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 KeyGenerator object.
+ *
+ * This is the same name that was specified in one of the
+ * getInstance calls that created this
+ * KeyGenerator object.
+ *
+ * @return the algorithm name of this KeyGenerator object.
+ */
+ public final String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * Generates a KeyGenerator object for the specified algorithm.
+ * If the default provider package provides an implementation of the
+ * requested key generator, an instance of KeyGenerator 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 KeyGenerator 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 KeyGenerator 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 KeyGenerator 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 KeyGenerator 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 KeyGenerator 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 KeyGenerator object.
+ *
+ * @return the provider of this KeyGenerator 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.
+ *
+ * If this key generator requires any random bytes, it will get them
+ * using the *
+ * SecureRandom 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 params 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.
+ *
+ * If this key generator requires any random bytes, it will get them using the
+ *
+ * SecureRandom 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/src/main/java/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java b/src/main/java/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java
new file mode 100644
index 0000000..0bb0b92
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/KeyGeneratorSpi.java
@@ -0,0 +1,65 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.SecretKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.InvalidParameterException;
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * This class defines the Service Provider Interface (SPI)
+ * for the KeyGenerator 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 javax.crypto.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 params 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/src/main/java/jce/src/main/java/javax/crypto/Mac.java b/src/main/java/jce/src/main/java/javax/crypto/Mac.java
new file mode 100644
index 0000000..f3cd6be
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/Mac.java
@@ -0,0 +1,446 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.JCEUtil;
+import jce.src.main.java.javax.crypto.MacSpi;
+import jce.src.main.java.javax.crypto.ShortBufferException;
+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.
+ *
+ * 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. + *
+ * 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 Mac object.
+ *
+ * This is the same name that was specified in one of the
+ * getInstance calls that created this Mac object.
+ *
+ * @return the algorithm name of this Mac object.
+ */
+ public final String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * Generates an Mac object that implements the
+ * specified MAC algorithm.
+ * If the default provider package provides an implementation of the
+ * requested MAC algorithm, an instance of
+ * Mac 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 Mac 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 Mac 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 Mac 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 Mac 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 Mac 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 Mac object.
+ *
+ * @return the provider of this Mac 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 Mac 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 Mac 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 Mac 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 Mac 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 len bytes in input,
+ * starting at offset inclusive.
+ *
+ * @param input the input buffer.
+ * @param offset the offset in input where the input starts.
+ * @param len the number of bytes to process.
+ * @exception IllegalStateException if this Mac 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.
+ *
+ * A call to this method resets this Mac object to the
+ * state it was in when previously initialized via a call to init(Key) or
+ * init(Key, AlgorithmParameterSpec).
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to update and
+ * doFinal.
+ * (In order to reuse this Mac object with a different key,
+ * it must be reinitialized via a call to init(Key) or
+ * init(Key, AlgorithmParameterSpec).
+ *
+ * @return the MAC result.
+ * @exception IllegalStateException if this Mac 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.
+ *
+ *
A call to this method resets this Mac object to the
+ * state it was in when previously initialized via a call to
+ * init(Key) or
+ * init(Key, AlgorithmParameterSpec).
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to update and
+ * doFinal.
+ * (In order to reuse this Mac object with a different key,
+ * it must be reinitialized via a call to init(Key) or
+ * init(Key, AlgorithmParameterSpec).
+ *
+ * The MAC result is stored in output, starting at
+ * outOffset inclusive.
+ *
+ * @param output the buffer where the MAC result is stored
+ * @param outOffset the offset in output where the MAC is stored
+ * @exception ShortBufferException if the given output buffer is too small to hold the result
+ * @exception IllegalStateException if this Mac 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.
+ *
+ * A call to this method resets this Mac object to the
+ * state it was in when previously initialized via a call to init(Key) or
+ * init(Key, AlgorithmParameterSpec). That is, the object is reset and
+ * available to generate another MAC from the same key, if desired, via new calls to
+ * update and doFinal.
+ * (In order to reuse this Mac object with a different key,
+ * it must be reinitialized via a call to init(Key) or
+ * init(Key, AlgorithmParameterSpec).
+ *
+ * @return the MAC result.
+ * @exception IllegalStateException if this Mac 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 Mac object.
+ *
+ * A call to this method resets this Mac object to the
+ * state it was in when previously initialized via a call to
+ * init(Key) or init(Key, AlgorithmParameterSpec).
+ * That is, the object is reset and available to generate another MAC from
+ * the same key, if desired, via new calls to update and
+ * doFinal.
+ * (In order to reuse this Mac object with a different key,
+ * it must be reinitialized via a call to init(Key) or
+ * init(Key, AlgorithmParameterSpec).
+ */
+ 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 Cloneable.
+ */
+ public final Object clone()
+ throws CloneNotSupportedException
+ {
+ Mac result = new Mac((MacSpi)macSpi.clone(), provider, algorithm);
+ result.initialised = initialised;
+ return result;
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/MacSpi.java b/src/main/java/jce/src/main/java/javax/crypto/MacSpi.java
new file mode 100644
index 0000000..e32ff20
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/MacSpi.java
@@ -0,0 +1,92 @@
+package jce.src.main.java.javax.crypto;
+
+import java.security.Key;
+import java.security.InvalidKeyException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class defines the Service Provider Interface (SPI)
+ * for the Mac 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.
+ *
+ * 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 len bytes in input,
+ * starting at offset inclusive.
+ *
+ * @param input the input buffer.
+ * @param offset the offset in input 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
+ * Cloneable.
+ */
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ throw new CloneNotSupportedException("Underlying MAC does not support cloning");
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/NoSuchPaddingException.java b/src/main/java/jce/src/main/java/javax/crypto/NoSuchPaddingException.java
new file mode 100644
index 0000000..33549a9
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/NoSuchPaddingException.java
@@ -0,0 +1,36 @@
+package jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/NullCipher.java b/src/main/java/jce/src/main/java/javax/crypto/NullCipher.java
new file mode 100644
index 0000000..4bcb4a4
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/NullCipher.java
@@ -0,0 +1,243 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.*;
+import jce.src.main.java.javax.crypto.Cipher;
+import jce.src.main.java.javax.crypto.CipherSpi;
+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 update
+ * or doFinal operation, given the input length
+ * inputLen (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/src/main/java/jce/src/main/java/javax/crypto/SealedObject.java b/src/main/java/jce/src/main/java/javax/crypto/SealedObject.java
new file mode 100644
index 0000000..9eebf1a
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/SealedObject.java
@@ -0,0 +1,306 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.BadPaddingException;
+import jce.src.main.java.javax.crypto.Cipher;
+import jce.src.main.java.javax.crypto.IllegalBlockSizeException;
+import jce.src.main.java.javax.crypto.NoSuchPaddingException;
+import java.io.*;
+import java.security.*;
+
+/**
+ * This class enables a programmer to create an object and protect its
+ * confidentiality with a cryptographic algorithm.
+ *
+ *
+ * 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. + * + *
+ * Note that the Cipher object must be fully initialized with the + * correct algorithm, key, padding scheme, etc., before being applied + * to a SealedObject. + * + *
+ * The original object that was sealed can be recovered in two different + * ways: + *
+ * + *
Cipher object.
+ *
+ *
+ * This method requires a fully initialized Cipher object,
+ * initialized with the
+ * exact same algorithm, key, padding scheme, etc., that were used to seal the
+ * object.
+ *
+ *
+ * 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. + * + *
+ * + *
Key object.
+ *
+ * In this approach, the getObject 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.
+ *
+ *
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. + * + *
+ * The given object is serialized, and its serialized contents are + * encrypted using the given Cipher, which must be fully initialized. + *
+ * Any algorithm parameters that may be used in the encryption
+ * operation are stored inside of the new SealedObject.
+ *
+ * @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,
+ jce.src.main.java.javax.crypto.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.
+ *
+ * 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
+ * key and the parameters (if any) that had been used in the
+ * sealing operation.
+ *
+ * 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. + *
+ * 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( + jce.src.main.java.javax.crypto.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. + *
+ * 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 provider.
+ * The Cipher object is initialized for decryption, using the given
+ * key and the parameters (if any) that had been used in the
+ * sealing operation.
+ *
+ * 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!"); + } + + jce.src.main.java.javax.crypto.Cipher cipher = null; + try + { + if (provider != null) + { + cipher = jce.src.main.java.javax.crypto.Cipher.getInstance(sealAlg, provider); + } + else + { + cipher = jce.src.main.java.javax.crypto.Cipher.getInstance(sealAlg); + } + } + catch (NoSuchPaddingException e) + { + throw new NoSuchAlgorithmException(e.getMessage()); + } + + if (paramsAlg == null) + { + cipher.init(jce.src.main.java.javax.crypto.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/src/main/java/jce/src/main/java/javax/crypto/SecretKey.java b/src/main/java/jce/src/main/java/javax/crypto/SecretKey.java new file mode 100644 index 0000000..bdd6925 --- /dev/null +++ b/src/main/java/jce/src/main/java/javax/crypto/SecretKey.java @@ -0,0 +1,30 @@ +package jce.src.main.java.javax.crypto; + +import jce.src.main.java.javax.crypto.Cipher; +import jce.src.main.java.javax.crypto.SecretKeyFactory; +import java.security.Key; + +/** + * A secret (symmetric) key. + *
+ * This interface contains no methods or constants. + * Its only purpose is to group (and provide type safety for) secret keys. + *
+ * Provider implementations of this interface must overwrite the
+ * equals and hashCode methods inherited from
+ * java.lang.Object, so that secret keys are compared based on
+ * their underlying key material and not based on reference.
+ *
+ * Keys that implement this interface return the string RAW
+ * as their encoding format (see getFormat), and return the
+ * raw key bytes as the result of a getEncoded method call. (The
+ * getFormat and getEncoded methods are inherited
+ * from the java.security.Key parent interface.)
+ *
+ * @see SecretKeyFactory
+ * @see Cipher
+ */
+public abstract interface SecretKey
+ extends Key
+{
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactory.java b/src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactory.java
new file mode 100644
index 0000000..240b3b4
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactory.java
@@ -0,0 +1,247 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.SecretKey;
+import jce.src.main.java.javax.crypto.SecretKeyFactorySpi;
+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.
+ *
+ *
+ * Key factories are used to convert keys (opaque
+ * cryptographic keys of type Key) into key specifications
+ * (transparent representations of the underlying key material), and vice versa.
+ * Secret key factories operate only on secret (symmetric) keys.
+ *
+ * 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. + *
+ * Application developers should refer to their provider's documentation
+ * to find out which key specifications are supported by the
+ * generateSecret and
+ * getKeySpec methods.
+ * For example, the DES secret-key factory supplied by the "SunJCE" provider
+ * supports DESKeySpec as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * DESedeKeySpec as a transparent representation of Triple DES keys.
+ *
+ * @see javax.crypto.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 SecretKeyFactory object for the specified secret-key algorithm.
+ * If the default provider package provides an implementation of the
+ * requested factory, an instance of SecretKeyFactory
+ * 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
+ * for information about standard algorithm names.
+ * @return a SecretKeyFactory 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 SecretKeyFactory 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 SecretKeyFactory 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 SecretKeyFactory 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 SecretKeyFactory 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 SecretKeyFactory object.
+ *
+ * @return the provider of this SecretKeyFactory object
+ */
+ public final Provider getProvider()
+ {
+ return provider;
+ }
+
+ /**
+ * Returns the algorithm name of this SecretKeyFactory object.
+ *
+ * This is the same name that was specified in one of the getInstance calls
+ * that created this SecretKeyFactory object.
+ *
+ * @return the algorithm name of this SecretKeyFactory object.
+ */
+ public final String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * Generates a SecretKey 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 jce.src.main.java.javax.crypto.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 key and keySpec do
+ * not match, or key references a key on a cryptographic hardware device whereas
+ * keySpec 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(
+ jce.src.main.java.javax.crypto.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 jce.src.main.java.javax.crypto.SecretKey translateKey(
+ SecretKey key)
+ throws InvalidKeyException
+ {
+ return keyFacSpi.engineTranslateKey(key);
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java b/src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java
new file mode 100644
index 0000000..3af8485
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/SecretKeyFactorySpi.java
@@ -0,0 +1,73 @@
+package jce.src.main.java.javax.crypto;
+
+import jce.src.main.java.javax.crypto.SecretKey;
+import java.security.InvalidKeyException;
+import java.security.spec.KeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+/**
+ * This class defines the Service Provider Interface (SPI)
+ * for the SecretKeyFactory 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.
+ *
+ * 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 DESKeySpec as a transparent representation of DES
+ * keys, and that provider's secret-key factory for Triple DES keys supports
+ * DESedeKeySpec as a transparent representation of Triple DES
+ * keys.
+ *
+ * @see javax.crypto.SecretKey
+ * @see javax.crypto.spec.DESKeySpec
+ * @see javax.crypto.spec.DESedeKeySpec
+ */
+public abstract class SecretKeyFactorySpi
+{
+ public SecretKeyFactorySpi()
+ {
+ }
+
+ /**
+ * Generates a SecretKey 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 jce.src.main.java.javax.crypto.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 key and keySpec do
+ * not match, or key references a key on a cryptographic hardware device whereas
+ * keySpec 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(
+ jce.src.main.java.javax.crypto.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 jce.src.main.java.javax.crypto.SecretKey engineTranslateKey(
+ SecretKey key)
+ throws InvalidKeyException;
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/ShortBufferException.java b/src/main/java/jce/src/main/java/javax/crypto/ShortBufferException.java
new file mode 100644
index 0000000..205fd66
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/ShortBufferException.java
@@ -0,0 +1,36 @@
+package jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHKey.java b/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHKey.java
new file mode 100644
index 0000000..67a84bf
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHKey.java
@@ -0,0 +1,22 @@
+package jce.src.main.java.javax.crypto.interfaces;
+
+import jce.src.main.java.javax.crypto.interfaces.DHPrivateKey;
+import jce.src.main.java.javax.crypto.interfaces.DHPublicKey;
+import jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java b/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java
new file mode 100644
index 0000000..4f12017
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPrivateKey.java
@@ -0,0 +1,23 @@
+package jce.src.main.java.javax.crypto.interfaces;
+
+import jce.src.main.java.javax.crypto.interfaces.DHKey;
+import jce.src.main.java.javax.crypto.interfaces.DHPublicKey;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * The interface to a Diffie-Hellman private key.
+ *
+ * @see javax.crypto.interfaces.DHKey
+ * @see DHPublicKey
+ */
+public abstract interface DHPrivateKey
+ extends DHKey, PrivateKey
+{
+ /**
+ * Returns the private value, x.
+ *
+ * @return the private value, x
+ */
+ public BigInteger getX();
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java b/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java
new file mode 100644
index 0000000..2bba6b3
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/interfaces/DHPublicKey.java
@@ -0,0 +1,23 @@
+package jce.src.main.java.javax.crypto.interfaces;
+
+import jce.src.main.java.javax.crypto.interfaces.DHKey;
+import jce.src.main.java.javax.crypto.interfaces.DHPrivateKey;
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * The interface to a Diffie-Hellman public key.
+ *
+ * @see javax.crypto.interfaces.DHKey
+ * @see DHPrivateKey
+ */
+public abstract interface DHPublicKey
+ extends DHKey, PublicKey
+{
+ /**
+ * Returns the public value, y.
+ *
+ * @return the public value, y
+ */
+ public BigInteger getY();
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/interfaces/PBEKey.java b/src/main/java/jce/src/main/java/javax/crypto/interfaces/PBEKey.java
new file mode 100644
index 0000000..24bb747
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/interfaces/PBEKey.java
@@ -0,0 +1,41 @@
+package jce.src.main.java.javax.crypto.interfaces;
+
+import jce.src.main.java.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/src/main/java/jce/src/main/java/javax/crypto/spec/DESKeySpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/DESKeySpec.java
new file mode 100644
index 0000000..996672d
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/DESKeySpec.java
@@ -0,0 +1,194 @@
+package jce.src.main.java.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 key as the key material for the DES key.
+ *
+ * The bytes that constitute the DES key are those between
+ * key[0] and key[7] 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 key, beginning at
+ * offset inclusive, as the key material for the DES key.
+ *
+ * The bytes that constitute the DES key are those between
+ * key[offset] and key[offset+7] inclusive.
+ *
+ * @param key the buffer with the DES key material.
+ * @param offset the offset in key, where the DES key material starts.
+ * @exception InvalidKeyException if the given key material, starting at
+ * offset 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 offset
+ * inclusive, is parity-adjusted.
+ *
+ * @param key the buffer with the DES key material.
+ * @param offset the offset in key, 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 offset
+ * 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 key, 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 offset
+ * 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/src/main/java/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java
new file mode 100644
index 0000000..1ef0a3c
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/DESedeKeySpec.java
@@ -0,0 +1,101 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import javax.crypto.spec.DESKeySpec;
+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 key as the DES-EDE key.
+ *
+ * The bytes that constitute the DES-EDE key are those between
+ * key[0] and key[23] 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 key, beginning at
+ * offset inclusive, as the DES-EDE key.
+ *
+ * The bytes that constitute the DES-EDE key are those between
+ * key[offset] and key[offset+23] inclusive.
+ * @param key the buffer with the DES-EDE key material.
+ * @param offset the offset in key, where the DES-EDE key
+ * material starts.
+ * @exception InvalidKeyException if the given key material, starting at
+ * offset 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 offset
+ * 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
+ * offset 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 (javax.crypto.spec.DESKeySpec.isParityAdjusted(key, offset)
+ && javax.crypto.spec.DESKeySpec.isParityAdjusted(key, offset + 8)
+ && DESKeySpec.isParityAdjusted(key, offset + 16));
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java
new file mode 100644
index 0000000..623ca34
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/DHGenParameterSpec.java
@@ -0,0 +1,56 @@
+package jce.src.main.java.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.
+ *
+ * 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 AlgorithmParameterGenerator
+ * 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/src/main/java/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java
new file mode 100644
index 0000000..f935f51
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/DHParameterSpec.java
@@ -0,0 +1,95 @@
+package jce.src.main.java.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: Diffie-Hellman Key-Agreement
+ * Standard.
+ *
+ * A central authority generates parameters and gives them to the two
+ * entities seeking to generate a secret key. The parameters are a prime
+ * p, a base g, and optionally the length
+ * in bits of the private value, l.
+ *
+ * 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
+ * p and a base generator g.
+ *
+ * @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
+ * p, a base generator g, and the size in bits,
+ * l, 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 p.
+ *
+ * @return the prime modulus p
+ */
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ /**
+ * Returns the base generator g.
+ *
+ * @return the base generator g
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ /**
+ * Returns the size in bits, l, of the random exponent
+ * (private value).
+ *
+ * @return the size in bits, l, of the random exponent
+ * (private value), or 0 if this size has not been set
+ */
+ public int getL()
+ {
+ return l;
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java
new file mode 100644
index 0000000..eb57cb2
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java
@@ -0,0 +1,62 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import javax.crypto.spec.DHPublicKeySpec;
+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 x, a prime
+ * modulus p, and a base generator g.
+ */
+ public DHPrivateKeySpec(
+ BigInteger x,
+ BigInteger p,
+ BigInteger g)
+ {
+ this.x = x;
+ this.p = p;
+ this.g = g;
+ }
+
+ /**
+ * Returns the private value x.
+ *
+ * @return the private value x
+ */
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ /**
+ * Returns the prime modulus p.
+ *
+ * @return the prime modulus p
+ */
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ /**
+ * Returns the base generator g.
+ *
+ * @return the base generator g
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java
new file mode 100644
index 0000000..3fa024c
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/DHPublicKeySpec.java
@@ -0,0 +1,62 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import javax.crypto.spec.DHPrivateKeySpec;
+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 y, a prime
+ * modulus p, and a base generator g.
+ */
+ public DHPublicKeySpec(
+ BigInteger y,
+ BigInteger p,
+ BigInteger g)
+ {
+ this.y = y;
+ this.p = p;
+ this.g = g;
+ }
+
+ /**
+ * Returns the public value y.
+ *
+ * @return the public value y
+ */
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ /**
+ * Returns the prime modulus p.
+ *
+ * @return the prime modulus p
+ */
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ /**
+ * Returns the base generator g.
+ *
+ * @return the base generator g
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+}
diff --git a/src/main/java/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java
new file mode 100644
index 0000000..6c378ac
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/IvParameterSpec.java
@@ -0,0 +1,75 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies an initialization vector (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 iv 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 len bytes in iv,
+ * beginning at offset inclusive, as the IV.
+ *
+ * The bytes that constitute the IV are those between
+ * iv[offset] and iv[offset+len-1] inclusive.
+ *
+ * @param iv the buffer with the IV
+ * @param offset the offset in iv 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/src/main/java/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
new file mode 100644
index 0000000..9f98e84
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
@@ -0,0 +1,104 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import javax.crypto.spec.PSource;
+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:
+ *
+ *
+ *
+ * RSAES-OAEP-params ::= SEQUENCE { hashAlgorithm [0] OAEP-PSSDigestAlgorithms
+ * DEFAULT sha1, maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1,
+ * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty }
+ *
+ *
+ *
+ * where
+ *
+ *
+ *
+ * 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 -- }
+ *
+ *
+ *
+ * @see javax.crypto.spec.PSource
+ */
+public class OAEPParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private String mdName;
+ private String mgfName;
+ private AlgorithmParameterSpec mgfSpec;
+ private javax.crypto.spec.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, javax.crypto.spec.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/src/main/java/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java
new file mode 100644
index 0000000..43d3a2f
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/PBEKeySpec.java
@@ -0,0 +1,223 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEParameterSpec;
+
+/**
+ * A user-chosen password that can be used with password-based encryption (PBE).
+ * + * The password can be viewed as some kind of raw key material, from which the + * encryption mechanism that uses it derives a cryptographic key. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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/src/main/java/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java new file mode 100644 index 0000000..8bf0a0e --- /dev/null +++ b/src/main/java/jce/src/main/java/javax/crypto/spec/PBEParameterSpec.java @@ -0,0 +1,55 @@ +package jce.src.main.java.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 + * PKCS #5 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/src/main/java/jce/src/main/java/javax/crypto/spec/PSource.java b/src/main/java/jce/src/main/java/javax/crypto/spec/PSource.java new file mode 100644 index 0000000..58e7435 --- /dev/null +++ b/src/main/java/jce/src/main/java/javax/crypto/spec/PSource.java @@ -0,0 +1,98 @@ +package jce.src.main.java.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. + * + *
+ *
+ * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-pSpecified PARAMETERS OCTET STRING },
+ * ... -- Allows for future expansion --
+ * }
+ *
+ */
+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 javax.crypto.spec.PSource.PSpecified DEFAULT = new javax.crypto.spec.PSource.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/src/main/java/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java
new file mode 100644
index 0000000..e3a9486
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/RC2ParameterSpec.java
@@ -0,0 +1,162 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the parameters used with the
+ * RC2
+ * algorithm.
+ * + * The parameters consist of an effective key size and optionally + * an 8-byte initialization vector (IV) (only in feedback mode). + *
+ * This class can be used to initialize a Cipher object that
+ * implements the RC2 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.
+ *
+ * The bytes that constitute the IV are those between
+ * iv[0] and iv[7] 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.
+ *
+ * The IV is taken from iv, starting at
+ * offset inclusive.
+ * The bytes that constitute the IV are those between
+ * iv[offset] and iv[offset+7] inclusive.
+ *
+ * @param effectiveKeyBits the effective key size in bits.
+ * @param iv the buffer with the IV.
+ * @param offset the offset in iv 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 null.)
+ *
+ * @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/src/main/java/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java
new file mode 100644
index 0000000..c179ed2
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/RC5ParameterSpec.java
@@ -0,0 +1,224 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the parameters used with the
+ * RC5
+ * algorithm.
+ *
+ * The parameters consist of a version number, a rounds count, a word + * size, and optionally an initialization vector (IV) (only in feedback mode). + *
+ * This class can be used to initialize a Cipher object that
+ * implements the RC5 algorithm as supplied by
+ * RSA Data Security, Inc. (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.
+ *
+ * Note that the size of the IV (block size) must be twice the word
+ * size. The bytes that constitute the IV are those between
+ * iv[0] and iv[2*(wordSize/8)-1] 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.
+ *
+ * The IV is taken from iv, starting at offset inclusive.
+ * Note that the size of the IV (block size), starting at
+ * offset inclusive, must be twice the word size.
+ * The bytes that constitute the IV are those between
+ * iv[offset] and iv[offset+2*(wordSize/8)-1]
+ * 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 iv 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 null.)
+ *
+ * @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/src/main/java/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java b/src/main/java/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java
new file mode 100644
index 0000000..6a89825
--- /dev/null
+++ b/src/main/java/jce/src/main/java/javax/crypto/spec/SecretKeySpec.java
@@ -0,0 +1,193 @@
+package jce.src.main.java.javax.crypto.spec;
+
+import javax.crypto.SecretKey;
+import java.security.spec.KeySpec;
+
+/**
+ * This class specifies a secret key in a provider-independent fashion.
+ *
+ * It can be used to construct a SecretKey from a byte array,
+ * without having to go through a (provider-based)
+ * SecretKeyFactory.
+ *
+ * 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. + *
+ * 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 key 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:
+ * DESKeySpec)
+ * 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
+ * len bytes of key, starting at
+ * offset inclusive.
+ *
+ * The bytes that constitute the secret key are those between key[offset] and
+ * key[offset+len-1] inclusive.
+ *
+ * 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 key 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: DESKeySpec)
+ * must be used.
+ *
+ * @param key the key material of the secret key.
+ * @param offset the offset in key 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 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;
+ }
+}
diff --git a/src/test/java/SM4HelperForConnection.java b/src/test/java/SM4HelperForConnection.java
new file mode 100644
index 0000000..5b134af
--- /dev/null
+++ b/src/test/java/SM4HelperForConnection.java
@@ -0,0 +1,61 @@
+import SM4.BC_SM4;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Random;
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 16:23 2021/7/21
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class SM4HelperForConnection {
+// public static byte[] encryptWithSM4(String secret,byte[] rawText){
+// try {
+// return BC_KeyManager.SM4Encrypt(secret,rawText);
+// } catch (NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException | NoSuchProviderException e) {
+// e.printStackTrace();
+// return null;
+// }
+// }
+//
+// public static byte[] decryptWithSM4(String secret,byte[] encText){
+// try {
+// return BC_KeyManager.SM4Decrypt(secret,encText);
+// } catch (IllegalBlockSizeException | NoSuchPaddingException | BadPaddingException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException e) {
+// e.printStackTrace();
+// return null;
+// }
+// }
+
+ public static byte[] encryptWithSM4(byte[] secretkey, byte[] origData) {
+ try {
+ return BC_SM4.encrypt_ECB_Padding(secretkey, origData);
+ } catch (Exception e){
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static byte[] decryptWithSM4(byte[] secretkey, byte[] crypted){
+ try {
+ return BC_SM4.decrypt_ECB_Padding(secretkey, crypted);
+ } catch (Exception e){
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+ /**
+ * 获取长度为16字节的随机种子/随机密钥
+ * @return
+ */
+ public static byte[] getRandomSeed(){
+ String secretKey=String.format("%016d",
+ Math.abs(new Random(System.currentTimeMillis()).nextLong()))
+ .substring(0,16);
+ return secretKey.getBytes(StandardCharsets.UTF_8);
+ }
+}
diff --git a/src/test/java/TestSM4.java b/src/test/java/TestSM4.java
new file mode 100644
index 0000000..5e7d302
--- /dev/null
+++ b/src/test/java/TestSM4.java
@@ -0,0 +1,36 @@
+import SM4.BC_SM4;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.util.Arrays;
+
+/*
+ * @Author: Wang Feng
+ * @Description:
+ * @Version: 1.0.0
+ * @Date: 10:26 2021/7/28
+ * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
+ */
+public class TestSM4 {
+ @Test
+ public void testSM4(){
+ try {
+ byte[] enc= BC_SM4.encrypt_ECB_Padding("1234567812345678".getBytes(StandardCharsets.UTF_8),
+ "wefree".getBytes(StandardCharsets.UTF_8));
+ System.out.println("enc: "+ Arrays.toString(enc));
+ System.out.println("enc: "+new String(enc));
+ byte[] dec=BC_SM4.decrypt_ECB_Padding("1234567812345678".getBytes(StandardCharsets.UTF_8),
+ enc);
+ System.out.println("dec: "+Arrays.toString(dec));
+ System.out.println("dec: "+new String(dec));
+ } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException |
+ jce.src.main.java.javax.crypto.NoSuchPaddingException
+ | jce.src.main.java.javax.crypto.IllegalBlockSizeException
+ | jce.src.main.java.javax.crypto.BadPaddingException e) {
+ e.printStackTrace();
+ }
+ }
+}