Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pkix/src/main/java/org/spongycastle/operator')
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java19
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java19
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java70
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/ContentSigner.java27
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java31
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java34
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java97
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java69
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java224
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java24
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java36
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java9
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/GenericKey.java41
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java29
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java9
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/InputExpander.java29
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java8
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java11
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java11
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/MacCalculator.java34
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java8
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java15
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/OperatorException.java24
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java21
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java29
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java36
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java17
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java24
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java17
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java15
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java19
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java19
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java34
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java13
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java13
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java51
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java60
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java82
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java144
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java25
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java40
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java144
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java82
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java11
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java22
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java32
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java24
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java39
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java47
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java49
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java51
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java36
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java23
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java14
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java73
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java160
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java312
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java114
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java133
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java157
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java33
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java65
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java154
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java433
-rw-r--r--pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java25
65 files changed, 3770 insertions, 0 deletions
diff --git a/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..2ed2f145
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class AsymmetricKeyUnwrapper
+ implements KeyUnwrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected AsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java
new file mode 100644
index 00000000..3de80226
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class AsymmetricKeyWrapper
+ implements KeyWrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected AsymmetricKeyWrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java b/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java
new file mode 100644
index 00000000..e96a906c
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java
@@ -0,0 +1,70 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.util.io.BufferingOutputStream;
+
+/**
+ * A class that explicitly buffers the data to be signed, sending it in one
+ * block when ready for signing.
+ */
+public class BufferingContentSigner
+ implements ContentSigner
+{
+ private final ContentSigner contentSigner;
+ private final OutputStream output;
+
+ /**
+ * Base constructor.
+ *
+ * @param contentSigner the content signer to be wrapped.
+ */
+ public BufferingContentSigner(ContentSigner contentSigner)
+ {
+ this.contentSigner = contentSigner;
+ this.output = new BufferingOutputStream(contentSigner.getOutputStream());
+ }
+
+ /**
+ * Base constructor.
+ *
+ * @param contentSigner the content signer to be wrapped.
+ * @param bufferSize the size of the internal buffer to use.
+ */
+ public BufferingContentSigner(ContentSigner contentSigner, int bufferSize)
+ {
+ this.contentSigner = contentSigner;
+ this.output = new BufferingOutputStream(contentSigner.getOutputStream(), bufferSize);
+ }
+
+ /**
+ * Return the algorithm identifier supported by this signer.
+ *
+ * @return algorithm identifier for the signature generated.
+ */
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentSigner.getAlgorithmIdentifier();
+ }
+
+ /**
+ * Return the buffering stream.
+ *
+ * @return the output stream used to accumulate the data.
+ */
+ public OutputStream getOutputStream()
+ {
+ return output;
+ }
+
+ /**
+ * Generate signature from internally buffered data.
+ *
+ * @return the signature calculated from the bytes written to the buffering stream.
+ */
+ public byte[] getSignature()
+ {
+ return contentSigner.getSignature();
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java b/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java
new file mode 100644
index 00000000..fcdeefc4
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java
@@ -0,0 +1,27 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface ContentSigner
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a signature. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Returns a signature based on the current data written to the stream, since the
+ * start or the last call to getSignature().
+ *
+ * @return bytes representing the signature.
+ */
+ byte[] getSignature();
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java b/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java
new file mode 100644
index 00000000..a139ebb2
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java
@@ -0,0 +1,31 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface ContentVerifier
+{
+ /**
+ * Return the algorithm identifier describing the signature
+ * algorithm and parameters this expander supports.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a signature for later verification. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * @param expected expected value of the signature on the data.
+ * @return true if the signature verifies, false otherwise
+ */
+ boolean verify(byte[] expected);
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java b/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java
new file mode 100644
index 00000000..9d91304a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java
@@ -0,0 +1,34 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+
+/**
+ * General interface for providers of ContentVerifier objects.
+ */
+public interface ContentVerifierProvider
+{
+ /**
+ * Return whether or not this verifier has a certificate associated with it.
+ *
+ * @return true if there is an associated certificate, false otherwise.
+ */
+ boolean hasAssociatedCertificate();
+
+ /**
+ * Return the associated certificate if there is one.
+ *
+ * @return a holder containing the associated certificate if there is one, null if there is not.
+ */
+ X509CertificateHolder getAssociatedCertificate();
+
+ /**
+ * Return a ContentVerifier that matches the passed in algorithm identifier,
+ *
+ * @param verifierAlgorithmIdentifier the algorithm and parameters required.
+ * @return a matching ContentVerifier
+ * @throws OperatorCreationException if the required ContentVerifier cannot be created.
+ */
+ ContentVerifier get(AlgorithmIdentifier verifierAlgorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
new file mode 100644
index 00000000..42d6665e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
@@ -0,0 +1,97 @@
+package org.spongycastle.operator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+public class DefaultDigestAlgorithmIdentifierFinder
+ implements DigestAlgorithmIdentifierFinder
+{
+ private static Map digestOids = new HashMap();
+ private static Map digestNameToOids = new HashMap();
+
+ static
+ {
+ //
+ // digests
+ //
+ digestOids.put(OIWObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);
+ digestOids.put(OIWObjectIdentifiers.md4WithRSA, PKCSObjectIdentifiers.md4);
+ digestOids.put(OIWObjectIdentifiers.sha1WithRSA, OIWObjectIdentifiers.idSHA1);
+
+ digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2);
+ digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);
+ digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5);
+ digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);
+
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, OIWObjectIdentifiers.idSHA1);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1);
+
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512);
+
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256);
+
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411);
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411);
+
+ digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
+ digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ digestNameToOids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ digestNameToOids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+
+ digestNameToOids.put("GOST3411", CryptoProObjectIdentifiers.gostR3411);
+
+ digestNameToOids.put("MD2", PKCSObjectIdentifiers.md2);
+ digestNameToOids.put("MD4", PKCSObjectIdentifiers.md4);
+ digestNameToOids.put("MD5", PKCSObjectIdentifiers.md5);
+
+ digestNameToOids.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+ digestNameToOids.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+ digestNameToOids.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+ }
+
+ public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId)
+ {
+ AlgorithmIdentifier digAlgId;
+
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ digAlgId = RSASSAPSSparams.getInstance(sigAlgId.getParameters()).getHashAlgorithm();
+ }
+ else
+ {
+ digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigAlgId.getAlgorithm()), DERNull.INSTANCE);
+ }
+
+ return digAlgId;
+ }
+
+ public AlgorithmIdentifier find(String digAlgName)
+ {
+ return new AlgorithmIdentifier((ASN1ObjectIdentifier)digestNameToOids.get(digAlgName), DERNull.INSTANCE);
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java b/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java
new file mode 100644
index 00000000..d830e5cc
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java
@@ -0,0 +1,69 @@
+package org.spongycastle.operator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.util.Integers;
+
+public class DefaultSecretKeySizeProvider
+ implements SecretKeySizeProvider
+{
+ public static final SecretKeySizeProvider INSTANCE = new DefaultSecretKeySizeProvider();
+
+ private static final Map KEY_SIZES;
+
+ static
+ {
+ Map keySizes = new HashMap();
+
+ keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
+
+ keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192));
+
+ keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
+ keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
+ keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+
+ keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
+ keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+ keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
+
+ keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
+
+ KEY_SIZES = Collections.unmodifiableMap(keySizes);
+ }
+
+ public int getKeySize(AlgorithmIdentifier algorithmIdentifier)
+ {
+ int keySize = getKeySize(algorithmIdentifier.getAlgorithm());
+
+ // just need the OID
+ if (keySize > 0)
+ {
+ return keySize;
+ }
+
+ // TODO: support OID/Parameter key sizes (e.g. RC2).
+
+ return -1;
+ }
+
+ public int getKeySize(ASN1ObjectIdentifier algorithm)
+ {
+ Integer keySize = (Integer)KEY_SIZES.get(algorithm);
+
+ if (keySize != null)
+ {
+ return keySize.intValue();
+ }
+
+ return -1;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
new file mode 100644
index 00000000..58608c8b
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
@@ -0,0 +1,224 @@
+package org.spongycastle.operator;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.bsi.BSIObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.util.Strings;
+
+public class DefaultSignatureAlgorithmIdentifierFinder
+ implements SignatureAlgorithmIdentifierFinder
+{
+ private static Map algorithms = new HashMap();
+ private static Set noParams = new HashSet();
+ private static Map params = new HashMap();
+ private static Set pkcs15RsaEncryption = new HashSet();
+ private static Map digestOids = new HashMap();
+
+ private static final ASN1ObjectIdentifier ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption;
+ private static final ASN1ObjectIdentifier ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1;
+ private static final ASN1ObjectIdentifier ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1;
+ private static final ASN1ObjectIdentifier ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS;
+ private static final ASN1ObjectIdentifier ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94;
+ private static final ASN1ObjectIdentifier ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001;
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("SHA1WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA1);
+ algorithms.put("SHA224WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA224);
+ algorithms.put("SHA256WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA256);
+ algorithms.put("SHA384WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA384);
+ algorithms.put("SHA512WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA512);
+ algorithms.put("RIPEMD160WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_RIPEMD160);
+ algorithms.put("SHA1WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+ algorithms.put("SHA224WITHPCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+ algorithms.put("SHA256WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+ algorithms.put("SHA384WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
+ algorithms.put("SHA512WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // PKCS 1.5 encrypted algorithms
+ //
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ params.put("SHA1WITHRSAANDMGF1", createPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ params.put("SHA256WITHRSAANDMGF1", createPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ params.put("SHA384WITHRSAANDMGF1", createPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ params.put("SHA512WITHRSAANDMGF1", createPSSParams(sha512AlgId, 64));
+
+ //
+ // digests
+ //
+ digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2);
+ digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);
+ digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5);
+ digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256);
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411);
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411);
+ }
+
+ private static AlgorithmIdentifier generate(String signatureAlgorithm)
+ {
+ AlgorithmIdentifier sigAlgId;
+ AlgorithmIdentifier encAlgId;
+ AlgorithmIdentifier digAlgId;
+
+ String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+ ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName);
+ if (sigOID == null)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + algorithmName);
+ }
+
+ if (noParams.contains(sigOID))
+ {
+ sigAlgId = new AlgorithmIdentifier(sigOID);
+ }
+ else if (params.containsKey(algorithmName))
+ {
+ sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+ }
+
+ if (pkcs15RsaEncryption.contains(sigOID))
+ {
+ encAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+ }
+ else
+ {
+ encAlgId = sigAlgId;
+ }
+
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ digAlgId = ((RSASSAPSSparams)sigAlgId.getParameters()).getHashAlgorithm();
+ }
+ else
+ {
+ digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigOID), DERNull.INSTANCE);
+ }
+
+ return sigAlgId;
+ }
+
+ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ public AlgorithmIdentifier find(String sigAlgName)
+ {
+ return generate(sigAlgName);
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java
new file mode 100644
index 00000000..1254c38e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface DigestAlgorithmIdentifierFinder
+{
+ /**
+ * Find the digest algorithm identifier that matches with
+ * the passed in signature algorithm identifier.
+ *
+ * @param sigAlgId the signature algorithm of interest.
+ * @return an algorithm identifier for the corresponding digest.
+ */
+ AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId);
+
+ /**
+ * Find the algorithm identifier that matches with
+ * the passed in digest name.
+ *
+ * @param digAlgName the name of the digest algorithm of interest.
+ * @return an algorithm identifier for the digest signature.
+ */
+ AlgorithmIdentifier find(String digAlgName);
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java b/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java
new file mode 100644
index 00000000..0bb4712f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java
@@ -0,0 +1,36 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to calculate a digest from
+ * a stream of output.
+ */
+public interface DigestCalculator
+{
+ /**
+ * Return the algorithm identifier representing the digest implemented by
+ * this calculator.
+ *
+ * @return algorithm id and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a digest. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Return the digest calculated on what has been written to the calculator's output stream.
+ *
+ * @return a digest.
+ */
+ byte[] getDigest();
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java b/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java
new file mode 100644
index 00000000..55a7c143
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java
@@ -0,0 +1,9 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface DigestCalculatorProvider
+{
+ DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/GenericKey.java b/pkix/src/main/java/org/spongycastle/operator/GenericKey.java
new file mode 100644
index 00000000..5446ce7b
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/GenericKey.java
@@ -0,0 +1,41 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public class GenericKey
+{
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Object representation;
+
+ /**
+ * @deprecated provide an AlgorithmIdentifier.
+ * @param representation key data
+ */
+ public GenericKey(Object representation)
+ {
+ this.algorithmIdentifier = null;
+ this.representation = representation;
+ }
+
+ public GenericKey(AlgorithmIdentifier algorithmIdentifier, byte[] representation)
+ {
+ this.algorithmIdentifier = algorithmIdentifier;
+ this.representation = representation;
+ }
+
+ protected GenericKey(AlgorithmIdentifier algorithmIdentifier, Object representation)
+ {
+ this.algorithmIdentifier = algorithmIdentifier;
+ this.representation = representation;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public Object getRepresentation()
+ {
+ return representation;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java b/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java
new file mode 100644
index 00000000..c55b3db0
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java
@@ -0,0 +1,29 @@
+package org.spongycastle.operator;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an InputStream that will decrypt a stream of encrypted data.
+ */
+public interface InputDecryptor
+{
+ /**
+ * Return the algorithm identifier describing the encryption
+ * algorithm and parameters this decryptor can process.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in input stream encIn, returning an input stream
+ * that decrypts what it reads from encIn before returning it.
+ *
+ * @param encIn InputStream containing encrypted input.
+ * @return an decrypting InputStream
+ */
+ InputStream getInputStream(InputStream encIn);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java b/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java
new file mode 100644
index 00000000..4ef7e9c0
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java
@@ -0,0 +1,9 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface InputDecryptorProvider
+{
+ public InputDecryptor get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/InputExpander.java b/pkix/src/main/java/org/spongycastle/operator/InputExpander.java
new file mode 100644
index 00000000..870e4807
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/InputExpander.java
@@ -0,0 +1,29 @@
+package org.spongycastle.operator;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an InputStream that will produce uncompressed data.
+ */
+public interface InputExpander
+{
+ /**
+ * Return the algorithm identifier describing the compression
+ * algorithm and parameters this expander supports.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in input stream comIn, returning an input stream
+ * that expands anything read in from comIn.
+ *
+ * @param comIn the compressed input data stream..
+ * @return an expanding InputStream.
+ */
+ InputStream getInputStream(InputStream comIn);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java b/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java
new file mode 100644
index 00000000..d38b813a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface InputExpanderProvider
+{
+ InputExpander get(AlgorithmIdentifier algorithm);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java
new file mode 100644
index 00000000..8e216230
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java
@@ -0,0 +1,11 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface KeyUnwrapper
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptionKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java
new file mode 100644
index 00000000..4b7986df
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java
@@ -0,0 +1,11 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface KeyWrapper
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java b/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java
new file mode 100644
index 00000000..df59ed65
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java
@@ -0,0 +1,34 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface MacCalculator
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * the MAC for later verification. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Return the calculated MAC based on what has been written to the stream.
+ *
+ * @return calculated MAC.
+ */
+ byte[] getMac();
+
+
+ /**
+ * Return the key used for calculating the MAC.
+ *
+ * @return the MAC key.
+ */
+ GenericKey getKey();
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java b/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java
new file mode 100644
index 00000000..a30773f2
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface MacCalculatorProvider
+{
+ public MacCalculator get(AlgorithmIdentifier algorithm);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java b/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java
new file mode 100644
index 00000000..4e7cadac
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java
@@ -0,0 +1,15 @@
+package org.spongycastle.operator;
+
+public class OperatorCreationException
+ extends OperatorException
+{
+ public OperatorCreationException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+
+ public OperatorCreationException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/OperatorException.java b/pkix/src/main/java/org/spongycastle/operator/OperatorException.java
new file mode 100644
index 00000000..32ce9e41
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/OperatorException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator;
+
+public class OperatorException
+ extends Exception
+{
+ private Throwable cause;
+
+ public OperatorException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public OperatorException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java b/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java
new file mode 100644
index 00000000..960d292f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.operator;
+
+import java.io.IOException;
+
+public class OperatorStreamException
+ extends IOException
+{
+ private Throwable cause;
+
+ public OperatorStreamException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java b/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java
new file mode 100644
index 00000000..0e10df9a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java
@@ -0,0 +1,29 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an OutputStream that will output compressed data.
+ */
+public interface OutputCompressor
+{
+ /**
+ * Return the algorithm identifier describing the compression
+ * algorithm and parameters this compressor uses.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in output stream comOut, returning an output stream
+ * that compresses anything passed in before sending on to comOut.
+ *
+ * @param comOut output stream for compressed output.
+ * @return a compressing OutputStream
+ */
+ OutputStream getOutputStream(OutputStream comOut);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java b/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java
new file mode 100644
index 00000000..595e3b75
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java
@@ -0,0 +1,36 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an OutputStream that will output encrypted data.
+ */
+public interface OutputEncryptor
+{
+ /**
+ * Return the algorithm identifier describing the encryption
+ * algorithm and parameters this encryptor uses.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in output stream encOut, returning an output stream
+ * that encrypts anything passed in before sending on to encOut.
+ *
+ * @param encOut output stream for encrypted output.
+ * @return an encrypting OutputStream
+ */
+ OutputStream getOutputStream(OutputStream encOut);
+
+ /**
+ * Return the key used for encrypting the output.
+ *
+ * @return the encryption key.
+ */
+ GenericKey getKey();
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java b/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java
new file mode 100644
index 00000000..56bfb47f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java
@@ -0,0 +1,17 @@
+package org.spongycastle.operator;
+
+/**
+ * Interface for ContentVerifiers that also support raw signatures that can be
+ * verified using the digest of the calculated data.
+ */
+public interface RawContentVerifier
+{
+ /**
+ * Verify that the expected signature value was derived from the passed in digest.
+ *
+ * @param digest digest calculated from the content.
+ * @param expected expected value of the signature
+ * @return true if the expected signature is derived from the digest, false otherwise.
+ */
+ boolean verify(byte[] digest, byte[] expected);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java b/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java
new file mode 100644
index 00000000..56cab04a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator;
+
+public class RuntimeOperatorException
+ extends RuntimeException
+{
+ private Throwable cause;
+
+ public RuntimeOperatorException(String msg)
+ {
+ super(msg);
+ }
+
+ public RuntimeOperatorException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java b/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java
new file mode 100644
index 00000000..cb2d6561
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java
@@ -0,0 +1,17 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface SecretKeySizeProvider
+{
+ int getKeySize(AlgorithmIdentifier algorithmIdentifier);
+
+ /**
+ * Return the key size implied by the OID, if one exists.
+ *
+ * @param algorithm the OID of the algorithm of interest.
+ * @return -1 if there is no fixed key size associated with the OID, or more information is required.
+ */
+ int getKeySize(ASN1ObjectIdentifier algorithm);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java
new file mode 100644
index 00000000..5c997bda
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java
@@ -0,0 +1,15 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface SignatureAlgorithmIdentifierFinder
+{
+ /**
+ * Find the signature algorithm identifier that matches with
+ * the passed in signature algorithm name.
+ *
+ * @param sigAlgName the name of the signature algorithm of interest.
+ * @return an algorithm identifier for the corresponding signature.
+ */
+ AlgorithmIdentifier find(String sigAlgName);
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..705a7671
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class SymmetricKeyUnwrapper
+ implements KeyUnwrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected SymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java
new file mode 100644
index 00000000..56ac7ef1
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class SymmetricKeyWrapper
+ implements KeyWrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected SymmetricKeyWrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java b/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java
new file mode 100644
index 00000000..7abd31be
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java
@@ -0,0 +1,34 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.KeyParameter;
+
+class AESUtil
+{
+ static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key)
+ {
+ int length = key.getKey().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException("illegal keysize in AES");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters absent
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..f9b8c09b
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java
@@ -0,0 +1,13 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.crypto.engines.AESWrapEngine;
+import org.spongycastle.crypto.params.KeyParameter;
+
+public class BcAESSymmetricKeyUnwrapper
+ extends BcSymmetricKeyUnwrapper
+{
+ public BcAESSymmetricKeyUnwrapper(KeyParameter wrappingKey)
+ {
+ super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java
new file mode 100644
index 00000000..62dc062f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java
@@ -0,0 +1,13 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.crypto.engines.AESWrapEngine;
+import org.spongycastle.crypto.params.KeyParameter;
+
+public class BcAESSymmetricKeyWrapper
+ extends BcSymmetricKeyWrapper
+{
+ public BcAESSymmetricKeyWrapper(KeyParameter wrappingKey)
+ {
+ super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..8fed9deb
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java
@@ -0,0 +1,51 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.AsymmetricKeyUnwrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public abstract class BcAsymmetricKeyUnwrapper
+ extends AsymmetricKeyUnwrapper
+{
+ private AsymmetricKeyParameter privateKey;
+
+ public BcAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey)
+ {
+ super(encAlgId);
+
+ this.privateKey = privateKey;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ AsymmetricBlockCipher keyCipher = createAsymmetricUnwrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ keyCipher.init(false, privateKey);
+ try
+ {
+ byte[] key = keyCipher.processBlock(encryptedKey, 0, encryptedKey.length);
+
+ if (encryptedKeyAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.des_EDE3_CBC))
+ {
+ return new GenericKey(encryptedKeyAlgorithm, key);
+ }
+ else
+ {
+ return new GenericKey(encryptedKeyAlgorithm, key);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new OperatorException("unable to recover secret key: " + e.getMessage(), e);
+ }
+ }
+
+ protected abstract AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java
new file mode 100644
index 00000000..8b5bb3e8
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java
@@ -0,0 +1,60 @@
+package org.spongycastle.operator.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.operator.AsymmetricKeyWrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public abstract class BcAsymmetricKeyWrapper
+ extends AsymmetricKeyWrapper
+{
+ private AsymmetricKeyParameter publicKey;
+ private SecureRandom random;
+
+ public BcAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey)
+ {
+ super(encAlgId);
+
+ this.publicKey = publicKey;
+ }
+
+ public BcAsymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ AsymmetricBlockCipher keyEncryptionCipher = createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm());
+
+ CipherParameters params = publicKey;
+ if (random != null)
+ {
+ params = new ParametersWithRandom(params, random);
+ }
+
+ try
+ {
+ byte[] keyEnc = OperatorUtils.getKeyBytes(encryptionKey);
+ keyEncryptionCipher.init(true, publicKey);
+ return keyEncryptionCipher.processBlock(keyEnc, 0, keyEnc.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new OperatorException("unable to encrypt contents key", e);
+ }
+ }
+
+ protected abstract AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm);
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java
new file mode 100644
index 00000000..7160adff
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java
@@ -0,0 +1,82 @@
+package org.spongycastle.operator.bc;
+
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public abstract class BcContentSignerBuilder
+{
+ private SecureRandom random;
+ private AlgorithmIdentifier sigAlgId;
+ private AlgorithmIdentifier digAlgId;
+
+ protected BcDigestProvider digestProvider;
+
+ public BcContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ {
+ this.sigAlgId = sigAlgId;
+ this.digAlgId = digAlgId;
+ this.digestProvider = BcDefaultDigestProvider.INSTANCE;
+ }
+
+ public BcContentSignerBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public ContentSigner build(AsymmetricKeyParameter privateKey)
+ throws OperatorCreationException
+ {
+ final Signer sig = createSigner(sigAlgId, digAlgId);
+
+ if (random != null)
+ {
+ sig.init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.init(true, privateKey);
+ }
+
+ return new ContentSigner()
+ {
+ private BcSignerOutputStream stream = new BcSignerOutputStream(sig);
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return sigAlgId;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getSignature()
+ {
+ try
+ {
+ return stream.getSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+
+ protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier algorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java
new file mode 100644
index 00000000..3b975e4f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java
@@ -0,0 +1,144 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public abstract class BcContentVerifierProviderBuilder
+{
+ protected BcDigestProvider digestProvider;
+
+ public BcContentVerifierProviderBuilder()
+ {
+ this.digestProvider = BcDefaultDigestProvider.INSTANCE;
+ }
+
+ public ContentVerifierProvider build(final X509CertificateHolder certHolder)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return true;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ AsymmetricKeyParameter publicKey = extractKeyParameters(certHolder.getSubjectPublicKeyInfo());
+ BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ return new SigVerifier(algorithm, stream);
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(final AsymmetricKeyParameter publicKey)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return false;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return null;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ return new SigVerifier(algorithm, stream);
+ }
+ };
+ }
+
+ private BcSignerOutputStream createSignatureStream(AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey)
+ throws OperatorCreationException
+ {
+ Signer sig = createSigner(algorithm);
+
+ sig.init(false, publicKey);
+
+ return new BcSignerOutputStream(sig);
+ }
+
+ /**
+ * Extract an AsymmetricKeyParameter from the passed in SubjectPublicKeyInfo structure.
+ *
+ * @param publicKeyInfo a publicKeyInfo structure describing the public key required.
+ * @return an AsymmetricKeyParameter object containing the appropriate public key.
+ * @throws IOException if the publicKeyInfo data cannot be parsed,
+ */
+ protected abstract AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException;
+
+ /**
+ * Create the correct signer for the algorithm identifier sigAlgId.
+ *
+ * @param sigAlgId the algorithm details for the signature we want to verify.
+ * @return a Signer object.
+ * @throws OperatorCreationException if the Signer cannot be constructed.
+ */
+ protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId)
+ throws OperatorCreationException;
+
+ private class SigVerifier
+ implements ContentVerifier
+ {
+ private BcSignerOutputStream stream;
+ private AlgorithmIdentifier algorithm;
+
+ SigVerifier(AlgorithmIdentifier algorithm, BcSignerOutputStream stream)
+ {
+ this.algorithm = algorithm;
+ this.stream = stream;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ if (stream == null)
+ {
+ throw new IllegalStateException("verifier not initialised");
+ }
+
+ return stream;
+ }
+
+ public boolean verify(byte[] expected)
+ {
+ return stream.verify(expected);
+ }
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java
new file mode 100644
index 00000000..db7b608d
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java
@@ -0,0 +1,25 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.signers.DSADigestSigner;
+import org.spongycastle.crypto.signers.DSASigner;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDSAContentSignerBuilder
+ extends BcContentSignerBuilder
+{
+ public BcDSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ {
+ super(sigAlgId, digAlgId);
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ throws OperatorCreationException
+ {
+ Digest dig = digestProvider.get(digAlgId);
+
+ return new DSADigestSigner(new DSASigner(), dig);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java
new file mode 100644
index 00000000..aaf25f4d
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java
@@ -0,0 +1,40 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.signers.DSADigestSigner;
+import org.spongycastle.crypto.signers.DSASigner;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDSAContentVerifierProviderBuilder
+ extends BcContentVerifierProviderBuilder
+{
+ private DigestAlgorithmIdentifierFinder digestAlgorithmFinder;
+
+ public BcDSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder)
+ {
+ this.digestAlgorithmFinder = digestAlgorithmFinder;
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId);
+ Digest dig = digestProvider.get(digAlg);
+
+ return new DSADigestSigner(new DSASigner(), dig);
+ }
+
+ protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ return PublicKeyFactory.createKey(publicKeyInfo);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java
new file mode 100644
index 00000000..dce50a9e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java
@@ -0,0 +1,144 @@
+package org.spongycastle.operator.bc;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.digests.MD4Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.RIPEMD128Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.RIPEMD256Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDefaultDigestProvider
+ implements BcDigestProvider
+{
+ private static final Map lookup = createTable();
+
+ private static Map createTable()
+ {
+ Map table = new HashMap();
+
+ table.put(OIWObjectIdentifiers.idSHA1, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA1Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA224Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha256, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA256Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha384, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA384Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha512, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA512Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.md5, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new MD5Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.md4, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new MD4Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.md2, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new MD2Digest();
+ }
+ });
+ table.put(CryptoProObjectIdentifiers.gostR3411, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new GOST3411Digest();
+ }
+ });
+ table.put(TeleTrusTObjectIdentifiers.ripemd128, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new RIPEMD128Digest();
+ }
+ });
+ table.put(TeleTrusTObjectIdentifiers.ripemd160, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new RIPEMD160Digest();
+ }
+ });
+ table.put(TeleTrusTObjectIdentifiers.ripemd256, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new RIPEMD256Digest();
+ }
+ });
+
+ return Collections.unmodifiableMap(table);
+ }
+
+ public static final BcDigestProvider INSTANCE = new BcDefaultDigestProvider();
+
+ private BcDefaultDigestProvider()
+ {
+
+ }
+
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException
+ {
+ BcDigestProvider extProv = (BcDigestProvider)lookup.get(digestAlgorithmIdentifier.getAlgorithm());
+
+ if (extProv == null)
+ {
+ throw new OperatorCreationException("cannot recognise digest");
+ }
+
+ return extProv.get(digestAlgorithmIdentifier);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java
new file mode 100644
index 00000000..8e0a12f6
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java
@@ -0,0 +1,82 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDigestCalculatorProvider
+ implements DigestCalculatorProvider
+{
+ private BcDigestProvider digestProvider = BcDefaultDigestProvider.INSTANCE;
+
+ public DigestCalculator get(final AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ Digest dig = digestProvider.get(algorithm);
+
+ final DigestOutputStream stream = new DigestOutputStream(dig);
+
+ return new DigestCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getDigest()
+ {
+ return stream.getDigest();
+ }
+ };
+ }
+
+ private class DigestOutputStream
+ extends OutputStream
+ {
+ private Digest dig;
+
+ DigestOutputStream(Digest dig)
+ {
+ this.dig = dig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ dig.update(bytes, off, len);
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ dig.update(bytes, 0, bytes.length);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ dig.update((byte)b);
+ }
+
+ byte[] getDigest()
+ {
+ byte[] d = new byte[dig.getDigestSize()];
+
+ dig.doFinal(d, 0);
+
+ return d;
+ }
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java
new file mode 100644
index 00000000..6eb930ee
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java
@@ -0,0 +1,11 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.operator.OperatorCreationException;
+
+public interface BcDigestProvider
+{
+ ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..99762353
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSAEngine;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+
+public class BcRSAAsymmetricKeyUnwrapper
+ extends BcAsymmetricKeyUnwrapper
+{
+ public BcRSAAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey)
+ {
+ super(encAlgId, privateKey);
+ }
+
+ protected AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm)
+ {
+ return new PKCS1Encoding(new RSAEngine());
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java
new file mode 100644
index 00000000..c2153e6d
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java
@@ -0,0 +1,32 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSAEngine;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+
+public class BcRSAAsymmetricKeyWrapper
+ extends BcAsymmetricKeyWrapper
+{
+ public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey)
+ {
+ super(encAlgId, publicKey);
+ }
+
+ public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ super(encAlgId, PublicKeyFactory.createKey(publicKeyInfo));
+ }
+
+ protected AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm)
+ {
+ return new PKCS1Encoding(new RSAEngine());
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java
new file mode 100644
index 00000000..d62543b0
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.signers.RSADigestSigner;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcRSAContentSignerBuilder
+ extends BcContentSignerBuilder
+{
+ public BcRSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ {
+ super(sigAlgId, digAlgId);
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ throws OperatorCreationException
+ {
+ Digest dig = digestProvider.get(digAlgId);
+
+ return new RSADigestSigner(dig);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java
new file mode 100644
index 00000000..e1fd6736
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java
@@ -0,0 +1,39 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.signers.RSADigestSigner;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcRSAContentVerifierProviderBuilder
+ extends BcContentVerifierProviderBuilder
+{
+ private DigestAlgorithmIdentifierFinder digestAlgorithmFinder;
+
+ public BcRSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder)
+ {
+ this.digestAlgorithmFinder = digestAlgorithmFinder;
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId);
+ Digest dig = digestProvider.get(digAlg);
+
+ return new RSADigestSigner(dig);
+ }
+
+ protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ return PublicKeyFactory.createKey(publicKeyInfo);
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java
new file mode 100644
index 00000000..f4cdf62b
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java
@@ -0,0 +1,47 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Signer;
+
+public class BcSignerOutputStream
+ extends OutputStream
+{
+ private Signer sig;
+
+ BcSignerOutputStream(Signer sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ sig.update(bytes, off, len);
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ sig.update(bytes, 0, bytes.length);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ sig.update((byte)b);
+ }
+
+ byte[] getSignature()
+ throws CryptoException
+ {
+ return sig.generateSignature();
+ }
+
+ boolean verify(byte[] expected)
+ {
+ return sig.verifySignature(expected);
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..da37cf1a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java
@@ -0,0 +1,49 @@
+package org.spongycastle.operator.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+
+public class BcSymmetricKeyUnwrapper
+ extends SymmetricKeyUnwrapper
+{
+ private SecureRandom random;
+ private Wrapper wrapper;
+ private KeyParameter wrappingKey;
+
+ public BcSymmetricKeyUnwrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey)
+ {
+ super(wrappingAlgorithm);
+
+ this.wrapper = wrapper;
+ this.wrappingKey = wrappingKey;
+ }
+
+ public BcSymmetricKeyUnwrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ wrapper.init(false, wrappingKey);
+
+ try
+ {
+ return new GenericKey(encryptedKeyAlgorithm, wrapper.unwrap(encryptedKey, 0, encryptedKey.length));
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new OperatorException("unable to unwrap key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java
new file mode 100644
index 00000000..a35de7d7
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java
@@ -0,0 +1,51 @@
+package org.spongycastle.operator.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyWrapper;
+
+public class BcSymmetricKeyWrapper
+ extends SymmetricKeyWrapper
+{
+ private SecureRandom random;
+ private Wrapper wrapper;
+ private KeyParameter wrappingKey;
+
+ public BcSymmetricKeyWrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey)
+ {
+ super(wrappingAlgorithm);
+
+ this.wrapper = wrapper;
+ this.wrappingKey = wrappingKey;
+ }
+
+ public BcSymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ byte[] contentEncryptionKeySpec = OperatorUtils.getKeyBytes(encryptionKey);
+
+ if (random == null)
+ {
+ wrapper.init(true, wrappingKey);
+ }
+ else
+ {
+ wrapper.init(true, new ParametersWithRandom(wrappingKey, random));
+ }
+
+ return wrapper.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java b/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java
new file mode 100644
index 00000000..9b7c9836
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java
@@ -0,0 +1,36 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.KeyParameter;
+
+class CamelliaUtil
+{
+ static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key)
+ {
+ int length = key.getKey().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "illegal keysize in Camellia");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters must be
+ // absent
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java b/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java
new file mode 100644
index 00000000..a53c4692
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java
@@ -0,0 +1,23 @@
+package org.spongycastle.operator.bc;
+
+import java.security.Key;
+
+import org.spongycastle.operator.GenericKey;
+
+class OperatorUtils
+{
+ static byte[] getKeyBytes(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return ((Key)key.getRepresentation()).getEncoded();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return (byte[])key.getRepresentation();
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java b/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java
new file mode 100644
index 00000000..4d977310
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java
@@ -0,0 +1,14 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+class SEEDUtil
+{
+ static AlgorithmIdentifier determineKeyEncAlg()
+ {
+ // parameters absent
+ return new AlgorithmIdentifier(
+ KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
new file mode 100644
index 00000000..98e2b929
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
@@ -0,0 +1,73 @@
+package org.spongycastle.operator.jcajce;
+
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+
+public class JcaAlgorithmParametersConverter
+{
+ public JcaAlgorithmParametersConverter()
+ {
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algId, AlgorithmParameters parameters)
+ throws InvalidAlgorithmParameterException
+ {
+ try
+ {
+ ASN1Encodable params = ASN1Primitive.fromByteArray(parameters.getEncoded());
+
+ return new AlgorithmIdentifier(algId, params);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidAlgorithmParameterException("unable to encode parameters object: " + e.getMessage());
+ }
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algorithm, AlgorithmParameterSpec algorithmSpec)
+ throws InvalidAlgorithmParameterException
+ {
+ if (algorithmSpec instanceof OAEPParameterSpec)
+ {
+ if (algorithmSpec.equals(OAEPParameterSpec.DEFAULT))
+ {
+ return new AlgorithmIdentifier(algorithm,
+ new RSAESOAEPparams(RSAESOAEPparams.DEFAULT_HASH_ALGORITHM, RSAESOAEPparams.DEFAULT_MASK_GEN_FUNCTION, RSAESOAEPparams.DEFAULT_P_SOURCE_ALGORITHM));
+ }
+ else
+ {
+ OAEPParameterSpec oaepSpec = (OAEPParameterSpec)algorithmSpec;
+ PSource pSource = oaepSpec.getPSource();
+
+ if (!oaepSpec.getMGFAlgorithm().equals(OAEPParameterSpec.DEFAULT.getMGFAlgorithm()))
+ {
+ throw new InvalidAlgorithmParameterException("only " + OAEPParameterSpec.DEFAULT.getMGFAlgorithm() + " mask generator supported.");
+ }
+
+ AlgorithmIdentifier hashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find(oaepSpec.getDigestAlgorithm());
+ AlgorithmIdentifier mgf1HashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find((((MGF1ParameterSpec)oaepSpec.getMGFParameters()).getDigestAlgorithm()));
+ return new AlgorithmIdentifier(algorithm,
+ new RSAESOAEPparams(hashAlgorithm, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, mgf1HashAlgorithm),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(((PSource.PSpecified)pSource).getValue()))));
+ }
+ }
+
+ throw new InvalidAlgorithmParameterException("unknown parameter spec passed.");
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java
new file mode 100644
index 00000000..f3a008dd
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java
@@ -0,0 +1,160 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaContentSignerBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private String signatureAlgorithm;
+ private AlgorithmIdentifier sigAlgId;
+
+ public JcaContentSignerBuilder(String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
+ }
+
+ public JcaContentSignerBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaContentSignerBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JcaContentSignerBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public ContentSigner build(PrivateKey privateKey)
+ throws OperatorCreationException
+ {
+ try
+ {
+ final Signature sig = helper.createSignature(sigAlgId);
+
+ if (random != null)
+ {
+ sig.initSign(privateKey, random);
+ }
+ else
+ {
+ sig.initSign(privateKey);
+ }
+
+ return new ContentSigner()
+ {
+ private SignatureOutputStream stream = new SignatureOutputStream(sig);
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return sigAlgId;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getSignature()
+ {
+ try
+ {
+ return stream.getSignature();
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e);
+ }
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ byte[] getSignature()
+ throws SignatureException
+ {
+ return sig.sign();
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
new file mode 100644
index 00000000..7b5690e4
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
@@ -0,0 +1,312 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RawContentVerifier;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaContentVerifierProviderBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+
+ public JcaContentVerifierProviderBuilder()
+ {
+ }
+
+ public JcaContentVerifierProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaContentVerifierProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public ContentVerifierProvider build(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return build(helper.convertCertificate(certHolder));
+ }
+
+ public ContentVerifierProvider build(final X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ final X509CertificateHolder certHolder;
+
+ try
+ {
+ certHolder = new JcaX509CertificateHolder(certificate);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e);
+ }
+
+ return new ContentVerifierProvider()
+ {
+ private SignatureOutputStream stream;
+
+ public boolean hasAssociatedCertificate()
+ {
+ return true;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ Signature sig = helper.createSignature(algorithm);
+
+ sig.initVerify(certificate.getPublicKey());
+
+ stream = new SignatureOutputStream(sig);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+
+ Signature rawSig = createRawSig(algorithm, certificate.getPublicKey());
+
+ if (rawSig != null)
+ {
+ return new RawSigVerifier(algorithm, stream, rawSig);
+ }
+ else
+ {
+ return new SigVerifier(algorithm, stream);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(final PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return false;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return null;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ SignatureOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ Signature rawSig = createRawSig(algorithm, publicKey);
+
+ if (rawSig != null)
+ {
+ return new RawSigVerifier(algorithm, stream, rawSig);
+ }
+ else
+ {
+ return new SigVerifier(algorithm, stream);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(SubjectPublicKeyInfo publicKey)
+ throws OperatorCreationException
+ {
+ return this.build(helper.convertPublicKey(publicKey));
+ }
+
+ private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ try
+ {
+ Signature sig = helper.createSignature(algorithm);
+
+ sig.initVerify(publicKey);
+
+ return new SignatureOutputStream(sig);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+ }
+
+ private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey)
+ {
+ Signature rawSig;
+ try
+ {
+ rawSig = helper.createRawSignature(algorithm);
+
+ if (rawSig != null)
+ {
+ rawSig.initVerify(publicKey);
+ }
+ }
+ catch (Exception e)
+ {
+ rawSig = null;
+ }
+ return rawSig;
+ }
+
+ private class SigVerifier
+ implements ContentVerifier
+ {
+ private SignatureOutputStream stream;
+ private AlgorithmIdentifier algorithm;
+
+ SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream)
+ {
+ this.algorithm = algorithm;
+ this.stream = stream;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ if (stream == null)
+ {
+ throw new IllegalStateException("verifier not initialised");
+ }
+
+ return stream;
+ }
+
+ public boolean verify(byte[] expected)
+ {
+ try
+ {
+ return stream.verify(expected);
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class RawSigVerifier
+ extends SigVerifier
+ implements RawContentVerifier
+ {
+ private Signature rawSignature;
+
+ RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature)
+ {
+ super(algorithm, stream);
+ this.rawSignature = rawSignature;
+ }
+
+ public boolean verify(byte[] digest, byte[] expected)
+ {
+ try
+ {
+ rawSignature.update(digest);
+
+ return rawSignature.verify(expected);
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ boolean verify(byte[] expected)
+ throws SignatureException
+ {
+ return sig.verify(expected);
+ }
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java
new file mode 100644
index 00000000..c734b866
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java
@@ -0,0 +1,114 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.Provider;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class JcaDigestCalculatorProviderBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+
+ public JcaDigestCalculatorProviderBuilder()
+ {
+ }
+
+ public JcaDigestCalculatorProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaDigestCalculatorProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public DigestCalculatorProvider build()
+ throws OperatorCreationException
+ {
+ return new DigestCalculatorProvider()
+ {
+ public DigestCalculator get(final AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ final DigestOutputStream stream;
+
+ try
+ {
+ MessageDigest dig = helper.createDigest(algorithm);
+
+ stream = new DigestOutputStream(dig);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+
+ return new DigestCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getDigest()
+ {
+ return stream.getDigest();
+ }
+ };
+ }
+ };
+ }
+
+ private class DigestOutputStream
+ extends OutputStream
+ {
+ private MessageDigest dig;
+
+ DigestOutputStream(MessageDigest dig)
+ {
+ this.dig = dig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ dig.update(bytes, off, len);
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ dig.update(bytes);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ dig.update((byte)b);
+ }
+
+ byte[] getDigest()
+ {
+ return dig.digest();
+ }
+ }
+} \ No newline at end of file
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..0b5cbf60
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java
@@ -0,0 +1,133 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.AsymmetricKeyUnwrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public class JceAsymmetricKeyUnwrapper
+ extends AsymmetricKeyUnwrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private Map extraMappings = new HashMap();
+ private PrivateKey privKey;
+
+ public JceAsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, PrivateKey privKey)
+ {
+ super(algorithmIdentifier);
+
+ this.privKey = privKey;
+ }
+
+ public JceAsymmetricKeyUnwrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyUnwrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current Unwrapper.
+ */
+ public JceAsymmetricKeyUnwrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ extraMappings.put(algorithm, algorithmName);
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ try
+ {
+ Key sKey = null;
+
+ Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings);
+ AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier());
+
+ try
+ {
+ if (algParams != null)
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, privKey, algParams);
+ }
+ else
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, privKey);
+ }
+ sKey = keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY);
+ }
+ catch (GeneralSecurityException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
+ if (sKey == null)
+ {
+ keyCipher.init(Cipher.DECRYPT_MODE, privKey);
+ sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId());
+ }
+
+ return new JceGenericKey(encryptedKeyAlgorithm, sKey);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("key invalid: " + e.getMessage(), e);
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new OperatorException("illegal blocksize: " + e.getMessage(), e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new OperatorException("bad padding: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
new file mode 100644
index 00000000..95eb3b9a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
@@ -0,0 +1,157 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.AsymmetricKeyWrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public class JceAsymmetricKeyWrapper
+ extends AsymmetricKeyWrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private Map extraMappings = new HashMap();
+ private PublicKey publicKey;
+ private SecureRandom random;
+
+ public JceAsymmetricKeyWrapper(PublicKey publicKey)
+ {
+ super(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()).getAlgorithm());
+
+ this.publicKey = publicKey;
+ }
+
+ public JceAsymmetricKeyWrapper(X509Certificate certificate)
+ {
+ this(certificate.getPublicKey());
+ }
+
+ /**
+ * Create a wrapper, overriding the algorithm type that is stored in the public key.
+ *
+ * @param algorithmIdentifier identifier for encryption algorithm to be used.
+ * @param publicKey the public key to be used.
+ */
+ public JceAsymmetricKeyWrapper(AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey)
+ {
+ super(algorithmIdentifier);
+
+ this.publicKey = publicKey;
+ }
+
+ public JceAsymmetricKeyWrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyWrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current Wrapper.
+ */
+ public JceAsymmetricKeyWrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ extraMappings.put(algorithm, algorithmName);
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), extraMappings);
+ AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier());
+
+ byte[] encryptedKeyBytes = null;
+
+ try
+ {
+ if (algParams != null)
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, algParams, random);
+ }
+ else
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, random);
+ }
+ encryptedKeyBytes = keyEncryptionCipher.wrap(OperatorUtils.getJceKey(encryptionKey));
+ }
+ catch (InvalidKeyException e)
+ {
+ }
+ catch (GeneralSecurityException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support WRAP (this appears to be only for asymmetric algorithms)
+ if (encryptedKeyBytes == null)
+ {
+ try
+ {
+ keyEncryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey, random);
+ encryptedKeyBytes = keyEncryptionCipher.doFinal(OperatorUtils.getJceKey(encryptionKey).getEncoded());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("unable to encrypt contents key", e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorException("unable to encrypt contents key", e);
+ }
+ }
+
+ return encryptedKeyBytes;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java
new file mode 100644
index 00000000..a11a535e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java
@@ -0,0 +1,33 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.Key;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.GenericKey;
+
+public class JceGenericKey
+ extends GenericKey
+{
+ /**
+ * Attempt to simplify the key representation if possible.
+ *
+ * @param key a provider based key
+ * @return the byte encoding if one exists, key object otherwise.
+ */
+ private static Object getRepresentation(Key key)
+ {
+ byte[] keyBytes = key.getEncoded();
+
+ if (keyBytes != null)
+ {
+ return keyBytes;
+ }
+
+ return key;
+ }
+
+ public JceGenericKey(AlgorithmIdentifier algorithmIdentifier, Key representation)
+ {
+ super(algorithmIdentifier, getRepresentation(representation));
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java
new file mode 100644
index 00000000..dd9e7e0a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java
@@ -0,0 +1,65 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+
+public class JceSymmetricKeyUnwrapper
+ extends SymmetricKeyUnwrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecretKey secretKey;
+
+ public JceSymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, SecretKey secretKey)
+ {
+ super(algorithmIdentifier);
+
+ this.secretKey = secretKey;
+ }
+
+ public JceSymmetricKeyUnwrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceSymmetricKeyUnwrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ try
+ {
+ Cipher keyCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ keyCipher.init(Cipher.UNWRAP_MODE, secretKey);
+
+ return new JceGenericKey(encryptedKeyAlgorithm, keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("key invalid in message.", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorException("can't find algorithm.", e);
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java
new file mode 100644
index 00000000..3689f6c2
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java
@@ -0,0 +1,154 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyWrapper;
+
+public class JceSymmetricKeyWrapper
+ extends SymmetricKeyWrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private SecretKey wrappingKey;
+
+ public JceSymmetricKeyWrapper(SecretKey wrappingKey)
+ {
+ super(determineKeyEncAlg(wrappingKey));
+
+ this.wrappingKey = wrappingKey;
+ }
+
+ public JceSymmetricKeyWrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceSymmetricKeyWrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceSymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ Key contentEncryptionKeySpec = OperatorUtils.getJceKey(encryptionKey);
+
+ Cipher keyEncryptionCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ try
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, wrappingKey, random);
+
+ return keyEncryptionCipher.wrap(contentEncryptionKeySpec);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorException("cannot wrap key: " + e.getMessage(), e);
+ }
+ }
+
+ private static AlgorithmIdentifier determineKeyEncAlg(SecretKey key)
+ {
+ String algorithm = key.getAlgorithm();
+
+ if (algorithm.startsWith("DES"))
+ {
+ return new AlgorithmIdentifier(new ASN1ObjectIdentifier(
+ "1.2.840.113549.1.9.16.3.6"), DERNull.INSTANCE);
+ }
+ else if (algorithm.startsWith("RC2"))
+ {
+ return new AlgorithmIdentifier(new ASN1ObjectIdentifier(
+ "1.2.840.113549.1.9.16.3.7"), new ASN1Integer(58));
+ }
+ else if (algorithm.startsWith("AES"))
+ {
+ int length = key.getEncoded().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException("illegal keysize in AES");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters absent
+ }
+ else if (algorithm.startsWith("SEED"))
+ {
+ // parameters absent
+ return new AlgorithmIdentifier(
+ KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+ else if (algorithm.startsWith("Camellia"))
+ {
+ int length = key.getEncoded().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "illegal keysize in Camellia");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters must be
+ // absent
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm");
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java
new file mode 100644
index 00000000..8f2776ae
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java
@@ -0,0 +1,433 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.bsi.BSIObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.jcajce.util.JcaJceUtils;
+import org.spongycastle.operator.OperatorCreationException;
+
+class OperatorHelper
+{
+ private static final Map oids = new HashMap();
+ private static final Map asymmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricKeyAlgNames = new HashMap();
+
+ static
+ {
+ //
+ // reverse mappings
+ //
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+ oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA1, "SHA1WITHPLAIN-ECDSA");
+ oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA224, "SHA224WITHPLAIN-ECDSA");
+ oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA256, "SHA256WITHPLAIN-ECDSA");
+ oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA384, "SHA384WITHPLAIN-ECDSA");
+ oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA512, "SHA512WITHPLAIN-ECDSA");
+ oids.put(BSIObjectIdentifiers.ecdsa_plain_RIPEMD160, "RIPEMD160WITHPLAIN-ECDSA");
+ oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1WITHCVC-ECDSA");
+ oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHCVC-ECDSA");
+ oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256WITHCVC-ECDSA");
+ oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384WITHCVC-ECDSA");
+ oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512WITHCVC-ECDSA");
+
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+
+ oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
+ oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
+ oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
+ oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
+ oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
+
+ asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
+
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2");
+ }
+
+ private JcaJceHelper helper;
+
+ OperatorHelper(JcaJceHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = null;
+
+ if (!extraAlgNames.isEmpty())
+ {
+ cipherName = (String)extraAlgNames.get(algorithm);
+ }
+
+ if (cipherName == null)
+ {
+ cipherName = (String)asymmetricWrapperAlgNames.get(algorithm);
+ }
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // try alternate for RSA
+ if (cipherName.equals("RSA/ECB/PKCS1Padding"))
+ {
+ try
+ {
+ return helper.createCipher("RSA/NONE/PKCS1Padding");
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ // Ignore
+ }
+ }
+ // Ignore
+ }
+ }
+
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = (String)symmetricWrapperAlgNames.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmParameters parameters;
+
+ if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ return null;
+ }
+
+ try
+ {
+ parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return null; // There's a good chance there aren't any!
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e);
+ }
+
+ try
+ {
+ parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e);
+ }
+
+ return parameters;
+ }
+
+ MessageDigest createDigest(AlgorithmIdentifier digAlgId)
+ throws GeneralSecurityException
+ {
+ MessageDigest dig;
+
+ try
+ {
+ dig = helper.createDigest(JcaJceUtils.getDigestAlgName(digAlgId.getAlgorithm()));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(digAlgId.getAlgorithm()) != null)
+ {
+ String digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm());
+
+ dig = helper.createDigest(digestAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return dig;
+ }
+
+ Signature createSignature(AlgorithmIdentifier sigAlgId)
+ throws GeneralSecurityException
+ {
+ Signature sig;
+
+ try
+ {
+ sig = helper.createSignature(getSignatureName(sigAlgId));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getAlgorithm()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
+
+ sig = helper.createSignature(signatureAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return sig;
+ }
+
+ public Signature createRawSignature(AlgorithmIdentifier algorithm)
+ {
+ Signature sig;
+
+ try
+ {
+ String algName = getSignatureName(algorithm);
+
+ algName = "NONE" + algName.substring(algName.indexOf("WITH"));
+
+ sig = helper.createSignature(algName);
+
+ // RFC 4056
+ // When the id-RSASSA-PSS algorithm identifier is used for a signature,
+ // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
+ if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ AlgorithmParameters params = helper.createAlgorithmParameters(algName);
+
+ JcaJceUtils.loadParameters(params, algorithm.getParameters());
+
+ PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
+ sig.setParameter(spec);
+ }
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+
+ return sig;
+ }
+
+ private static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return JcaJceUtils.getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1";
+ }
+ }
+
+ if (oids.containsKey(sigAlgId.getAlgorithm()))
+ {
+ return (String)oids.get(sigAlgId.getAlgorithm());
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ public X509Certificate convertCertificate(X509CertificateHolder certHolder)
+ throws CertificateException
+ {
+
+ try
+ {
+ CertificateFactory certFact = helper.createCertificateFactory("X.509");
+
+ return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ }
+
+ public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws OperatorCreationException
+ {
+ try
+ {
+ KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId());
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ }
+
+ // TODO: put somewhere public so cause easily accessed
+ private static class OpCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public OpCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+
+ String getKeyAlgorithmName(ASN1ObjectIdentifier oid)
+ {
+
+ String name = (String)symmetricKeyAlgNames.get(oid);
+
+ if (name != null)
+ {
+ return name;
+ }
+
+ return oid.getId();
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java
new file mode 100644
index 00000000..81cb4063
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java
@@ -0,0 +1,25 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.Key;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.operator.GenericKey;
+
+class OperatorUtils
+{
+ static Key getJceKey(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return (Key)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new SecretKeySpec((byte[])key.getRepresentation(), "ENC");
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+} \ No newline at end of file