aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/mail/src/main/java/org/spongycastle/mail/smime/SMIMEEnvelopedGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/mail/src/main/java/org/spongycastle/mail/smime/SMIMEEnvelopedGenerator.java')
-rw-r--r--libraries/spongycastle/mail/src/main/java/org/spongycastle/mail/smime/SMIMEEnvelopedGenerator.java272
1 files changed, 272 insertions, 0 deletions
diff --git a/libraries/spongycastle/mail/src/main/java/org/spongycastle/mail/smime/SMIMEEnvelopedGenerator.java b/libraries/spongycastle/mail/src/main/java/org/spongycastle/mail/smime/SMIMEEnvelopedGenerator.java
new file mode 100644
index 000000000..3dfe78ec8
--- /dev/null
+++ b/libraries/spongycastle/mail/src/main/java/org/spongycastle/mail/smime/SMIMEEnvelopedGenerator.java
@@ -0,0 +1,272 @@
+package org.bouncycastle.mail.smime;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.activation.CommandMap;
+import javax.activation.MailcapCommandMap;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.cms.CMSEnvelopedDataStreamGenerator;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.RecipientInfoGenerator;
+import org.bouncycastle.operator.OutputEncryptor;
+
+/**
+ * General class for generating a pkcs7-mime message.
+ *
+ * A simple example of usage.
+ *
+ * <pre>
+ * SMIMEEnvelopedGenerator fact = new SMIMEEnvelopedGenerator();
+ *
+ * fact.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("BC"));
+ *
+ * MimeBodyPart mp = fact.generate(content, new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC, 40).setProvider("BC").build());
+ * </pre>
+ *
+ * <b>Note:<b> Most clients expect the MimeBodyPart to be in a MimeMultipart
+ * when it's sent.
+ */
+public class SMIMEEnvelopedGenerator
+ extends SMIMEGenerator
+{
+ public static final String DES_EDE3_CBC = CMSEnvelopedDataGenerator.DES_EDE3_CBC;
+ public static final String RC2_CBC = CMSEnvelopedDataGenerator.RC2_CBC;
+ public static final String IDEA_CBC = CMSEnvelopedDataGenerator.IDEA_CBC;
+ public static final String CAST5_CBC = CMSEnvelopedDataGenerator.CAST5_CBC;
+
+ public static final String AES128_CBC = CMSEnvelopedDataGenerator.AES128_CBC;
+ public static final String AES192_CBC = CMSEnvelopedDataGenerator.AES192_CBC;
+ public static final String AES256_CBC = CMSEnvelopedDataGenerator.AES256_CBC;
+
+ public static final String CAMELLIA128_CBC = CMSEnvelopedDataGenerator.CAMELLIA128_CBC;
+ public static final String CAMELLIA192_CBC = CMSEnvelopedDataGenerator.CAMELLIA192_CBC;
+ public static final String CAMELLIA256_CBC = CMSEnvelopedDataGenerator.CAMELLIA256_CBC;
+
+ public static final String SEED_CBC = CMSEnvelopedDataGenerator.SEED_CBC;
+
+ public static final String DES_EDE3_WRAP = CMSEnvelopedDataGenerator.DES_EDE3_WRAP;
+ public static final String AES128_WRAP = CMSEnvelopedDataGenerator.AES128_WRAP;
+ public static final String AES256_WRAP = CMSEnvelopedDataGenerator.AES256_WRAP;
+ public static final String CAMELLIA128_WRAP = CMSEnvelopedDataGenerator.CAMELLIA128_WRAP;
+ public static final String CAMELLIA192_WRAP = CMSEnvelopedDataGenerator.CAMELLIA192_WRAP;
+ public static final String CAMELLIA256_WRAP = CMSEnvelopedDataGenerator.CAMELLIA256_WRAP;
+ public static final String SEED_WRAP = CMSEnvelopedDataGenerator.SEED_WRAP;
+
+ public static final String ECDH_SHA1KDF = CMSEnvelopedDataGenerator.ECDH_SHA1KDF;
+
+ private static final String ENCRYPTED_CONTENT_TYPE = "application/pkcs7-mime; name=\"smime.p7m\"; smime-type=enveloped-data";
+
+ private EnvelopedGenerator fact;
+ private List recipients = new ArrayList();
+
+ static
+ {
+ CommandMap.setDefaultCommandMap(addCommands(CommandMap.getDefaultCommandMap()));
+ }
+
+ private static MailcapCommandMap addCommands(CommandMap cm)
+ {
+ MailcapCommandMap mc = (MailcapCommandMap)cm;
+
+ mc.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
+ mc.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
+ mc.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
+ mc.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
+ mc.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
+
+ return mc;
+ }
+
+ /**
+ * base constructor
+ */
+ public SMIMEEnvelopedGenerator()
+ {
+ fact = new EnvelopedGenerator();
+ }
+
+ /**
+ * add a recipientInfoGenerator.
+ */
+ public void addRecipientInfoGenerator(
+ RecipientInfoGenerator recipientInfoGen)
+ throws IllegalArgumentException
+ {
+ fact.addRecipientInfoGenerator(recipientInfoGen);
+ }
+
+ /**
+ * Use a BER Set to store the recipient information
+ */
+ public void setBerEncodeRecipients(
+ boolean berEncodeRecipientSet)
+ {
+ fact.setBEREncodeRecipients(berEncodeRecipientSet);
+ }
+
+ /**
+ * if we get here we expect the Mime body part to be well defined.
+ */
+ private MimeBodyPart make(
+ MimeBodyPart content,
+ OutputEncryptor encryptor)
+ throws SMIMEException
+ {
+ try
+ {
+ MimeBodyPart data = new MimeBodyPart();
+
+ data.setContent(new ContentEncryptor(content, encryptor), ENCRYPTED_CONTENT_TYPE);
+ data.addHeader("Content-Type", ENCRYPTED_CONTENT_TYPE);
+ data.addHeader("Content-Disposition", "attachment; filename=\"smime.p7m\"");
+ data.addHeader("Content-Description", "S/MIME Encrypted Message");
+ data.addHeader("Content-Transfer-Encoding", encoding);
+
+ return data;
+ }
+ catch (MessagingException e)
+ {
+ throw new SMIMEException("exception putting multi-part together.", e);
+ }
+ }
+
+ /**
+ * generate an enveloped object that contains an SMIME Enveloped
+ * object using the given content encryptor
+ */
+ public MimeBodyPart generate(
+ MimeBodyPart content,
+ OutputEncryptor encryptor)
+ throws SMIMEException
+ {
+ return make(makeContentBodyPart(content), encryptor);
+ }
+
+ /**
+ * generate an enveloped object that contains an SMIME Enveloped
+ * object using the given provider from the contents of the passed in
+ * message
+ */
+ public MimeBodyPart generate(
+ MimeMessage message,
+ OutputEncryptor encryptor)
+ throws SMIMEException
+ {
+ try
+ {
+ message.saveChanges(); // make sure we're up to date.
+ }
+ catch (MessagingException e)
+ {
+ throw new SMIMEException("unable to save message", e);
+ }
+
+ return make(makeContentBodyPart(message), encryptor);
+ }
+
+ private class ContentEncryptor
+ implements SMIMEStreamingProcessor
+ {
+ private final MimeBodyPart _content;
+ private OutputEncryptor _encryptor;
+
+ private boolean _firstTime = true;
+
+ ContentEncryptor(
+ MimeBodyPart content,
+ OutputEncryptor encryptor)
+ {
+ _content = content;
+ _encryptor = encryptor;
+ }
+
+ public void write(OutputStream out)
+ throws IOException
+ {
+ OutputStream encrypted;
+
+ try
+ {
+ if (_firstTime)
+ {
+ encrypted = fact.open(out, _encryptor);
+
+ _firstTime = false;
+ }
+ else
+ {
+ encrypted = fact.regenerate(out, _encryptor);
+ }
+
+ _content.getDataHandler().setCommandMap(addCommands(CommandMap.getDefaultCommandMap()));
+
+ _content.writeTo(encrypted);
+
+ encrypted.close();
+ }
+ catch (MessagingException e)
+ {
+ throw new WrappingIOException(e.toString(), e);
+ }
+ catch (CMSException e)
+ {
+ throw new WrappingIOException(e.toString(), e);
+ }
+ }
+ }
+
+ private class EnvelopedGenerator
+ extends CMSEnvelopedDataStreamGenerator
+ {
+ private ASN1ObjectIdentifier dataType;
+ private ASN1EncodableVector recipientInfos;
+
+ protected OutputStream open(
+ ASN1ObjectIdentifier dataType,
+ OutputStream out,
+ ASN1EncodableVector recipientInfos,
+ OutputEncryptor encryptor)
+ throws IOException
+ {
+ this.dataType = dataType;
+ this.recipientInfos = recipientInfos;
+
+ return super.open(dataType, out, recipientInfos, encryptor);
+ }
+
+ OutputStream regenerate(
+ OutputStream out,
+ OutputEncryptor encryptor)
+ throws IOException
+ {
+ return super.open(dataType, out, recipientInfos, encryptor);
+ }
+ }
+
+ private static class WrappingIOException
+ extends IOException
+ {
+ private Throwable cause;
+
+ WrappingIOException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}