Exemple #1
0
        /// <summary>
        /// Encrypts the specified entity.
        /// </summary>
        /// <remarks>
        /// Encrypts the entity to the specified recipients using the supplied <see cref="SecureMimeContext"/>.
        /// </remarks>
        /// <returns>The encrypted entity.</returns>
        /// <param name="ctx">The S/MIME context to use for encrypting.</param>
        /// <param name="recipients">The recipients.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="recipients"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// Valid certificates could not be found for one or more of the <paramref name="recipients"/>.
        /// </exception>
        /// <exception cref="CertificateNotFoundException">
        /// A certificate could not be found for one or more of the <paramref name="recipients"/>.
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime Encrypt(SecureMimeContext ctx, IEnumerable <MailboxAddress> recipients, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (recipients == null)
            {
                throw new ArgumentNullException(nameof(recipients));
            }

            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            using (var memory = new MemoryBlockStream()) {
                var options = FormatOptions.CloneDefault();
                options.NewLineFormat = NewLineFormat.Dos;

                entity.WriteTo(options, memory);
                memory.Position = 0;

                return((ApplicationPkcs7Mime)ctx.Encrypt(recipients, memory));
            }
        }
Exemple #2
0
        /// <summary>
        /// Cryptographically signs the specified entity.
        /// </summary>
        /// <remarks>
        /// <para>Signs the entity using the supplied signer and <see cref="SecureMimeContext"/>.</para>
        /// <para>For better interoperability with other mail clients, you should use
        /// <see cref="MultipartSigned.Create(SecureMimeContext, CmsSigner, MimeEntity)"/>
        /// instead as the multipart/signed format is supported among a much larger
        /// subset of mail client software.</para>
        /// </remarks>
        /// <returns>The signed entity.</returns>
        /// <param name="ctx">The S/MIME context to use for signing.</param>
        /// <param name="signer">The signer.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="signer"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime Sign(SecureMimeContext ctx, CmsSigner signer, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            using (var memory = new MemoryBlockStream()) {
                var options = FormatOptions.CloneDefault();
                options.NewLineFormat = NewLineFormat.Dos;

                entity.WriteTo(options, memory);
                memory.Position = 0;

                return(ctx.EncapsulatedSign(signer, memory));
            }
        }
Exemple #3
0
        static EncryptionAlgorithm[] DecodeEncryptionAlgorithms(byte[] rawData)
        {
            using (var memory = new MemoryStream(rawData, false)) {
                using (var asn1 = new Asn1InputStream(memory)) {
                    var algorithms = new List <EncryptionAlgorithm> ();
                    var sequence   = asn1.ReadObject() as Asn1Sequence;

                    if (sequence == null)
                    {
                        return(null);
                    }

                    for (int i = 0; i < sequence.Count; i++)
                    {
                        var identifier = AlgorithmIdentifier.GetInstance(sequence[i]);
                        EncryptionAlgorithm algorithm;

                        if (SecureMimeContext.TryGetEncryptionAlgorithm(identifier, out algorithm))
                        {
                            algorithms.Add(algorithm);
                        }
                    }

                    return(algorithms.ToArray());
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Creates a new <see cref="MultipartSigned"/>.
        /// </summary>
        /// <remarks>
        /// Cryptographically signs the entity using the supplied signer in order
        /// to generate a detached signature and then adds the entity along with
        /// the detached signature data to a new multipart/signed part.
        /// </remarks>
        /// <returns>A new <see cref="MultipartSigned"/> instance.</returns>
        /// <param name="ctx">The S/MIME context to use for signing.</param>
        /// <param name="signer">The signer.</param>
        /// <param name="entity">The entity to sign.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="signer"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static MultipartSigned Create(SecureMimeContext ctx, CmsSigner signer, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (signer == null)
            {
                throw new ArgumentNullException(nameof(signer));
            }

            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            using (var memory = new MemoryBlockStream()) {
                var prepared = Prepare(entity, memory);

                memory.Position = 0;

                // sign the cleartext content
                var signature = ctx.Sign(signer, memory);

                return(Create(ctx, signer.DigestAlgorithm, prepared, signature));
            }
        }
Exemple #5
0
        /// <summary>
        /// Cryptographically signs the specified entity.
        /// </summary>
        /// <remarks>
        /// <para>Signs the entity using the supplied signer, digest algorithm and <see cref="SecureMimeContext"/>.</para>
        /// <para>For better interoperability with other mail clients, you should use
        /// <see cref="MultipartSigned.Create(SecureMimeContext, CmsSigner, MimeEntity)"/>
        /// instead as the multipart/signed format is supported among a much larger
        /// subset of mail client software.</para>
        /// </remarks>
        /// <returns>The signed entity.</returns>
        /// <param name="ctx">The S/MIME context to use for signing.</param>
        /// <param name="signer">The signer.</param>
        /// <param name="digestAlgo">The digest algorithm to use for signing.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="signer"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="CertificateNotFoundException">
        /// A signing certificate could not be found for <paramref name="signer"/>.
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime Sign(SecureMimeContext ctx, MailboxAddress signer, DigestAlgorithm digestAlgo, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (signer == null)
            {
                throw new ArgumentNullException("signer");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            using (var memory = new MemoryBlockStream()) {
                var options = FormatOptions.CloneDefault();
                options.NewLineFormat = NewLineFormat.Dos;

                entity.WriteTo(options, memory);
                memory.Position = 0;

                return(ctx.EncapsulatedSign(signer, digestAlgo, memory));
            }
        }
Exemple #6
0
        /// <summary>
        /// Encrypts the specified entity.
        /// </summary>
        /// <remarks>
        /// Encrypts the entity to the specified recipients using the supplied <see cref="SecureMimeContext"/>.
        /// </remarks>
        /// <returns>The encrypted entity.</returns>
        /// <param name="ctx">The S/MIME context to use for encrypting.</param>
        /// <param name="recipients">The recipients.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="recipients"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime Encrypt(SecureMimeContext ctx, CmsRecipientCollection recipients, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (recipients == null)
            {
                throw new ArgumentNullException("recipients");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            using (var memory = new MemoryBlockStream()) {
                var options = FormatOptions.CloneDefault();
                options.NewLineFormat = NewLineFormat.Dos;

                entity.WriteTo(options, memory);
                memory.Position = 0;

                return(ctx.Encrypt(recipients, memory));
            }
        }
        /// <summary>
        /// Creates a new <see cref="MultipartSigned"/>.
        /// </summary>
        /// <remarks>
        /// Cryptographically signs the entity using the supplied signer in order
        /// to generate a detached signature and then adds the entity along with
        /// the detached signature data to a new multipart/signed part.
        /// </remarks>
        /// <returns>A new <see cref="MultipartSigned"/> instance.</returns>
        /// <param name="ctx">The S/MIME context to use for signing.</param>
        /// <param name="signer">The signer.</param>
        /// <param name="entity">The entity to sign.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="signer"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static MultipartSigned Create(SecureMimeContext ctx, CmsSigner signer, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (signer == null)
            {
                throw new ArgumentNullException("signer");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            entity.Prepare(EncodingConstraint.SevenBit, 78);

            using (var memory = new MemoryBlockStream()) {
                using (var filtered = new FilteredStream(memory)) {
                    // Note: see rfc3156, section 3 - second note
                    filtered.Add(new ArmoredFromFilter());

                    // Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156)
                    filtered.Add(new TrailingWhitespaceFilter());

                    // Note: see rfc2015 or rfc3156, section 5.1
                    filtered.Add(new Unix2DosFilter());

                    entity.WriteTo(filtered);
                    filtered.Flush();
                }

                memory.Position = 0;

                // Note: we need to parse the modified entity structure to preserve any modifications
                var parser = new MimeParser(memory, MimeFormat.Entity);
                var parsed = parser.ParseEntity();
                memory.Position = 0;

                // sign the cleartext content
                var micalg    = ctx.GetDigestAlgorithmName(signer.DigestAlgorithm);
                var signature = ctx.Sign(signer, memory);
                var signed    = new MultipartSigned();

                // set the protocol and micalg Content-Type parameters
                signed.ContentType.Parameters["protocol"] = ctx.SignatureProtocol;
                signed.ContentType.Parameters["micalg"]   = micalg;

                // add the modified/parsed entity as our first part
                signed.Add(parsed);

                // add the detached signature as the second part
                signed.Add(signature);

                return(signed);
            }
        }
        internal RsaesOaepParameters GetRsaesOaepParameters()
        {
            if (OaepHashAlgorithm == DigestAlgorithm.Sha1)
            {
                return(new RsaesOaepParameters());
            }

            var oid             = SecureMimeContext.GetDigestOid(OaepHashAlgorithm);
            var hashAlgorithm   = new AlgorithmIdentifier(new DerObjectIdentifier(oid), DerNull.Instance);
            var maskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgorithm);

            return(new RsaesOaepParameters(hashAlgorithm, maskGenFunction, RsaesOaepParameters.DefaultPSourceAlgorithm));
        }
Exemple #9
0
        /// <summary>
        /// Imports the certificates contained in the content.
        /// </summary>
        /// <remarks>
        /// Imports the certificates contained in the content.
        /// </remarks>
        /// <param name="ctx">The S/MIME context to import certificates into.</param>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "certs-only".
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public void Import(SecureMimeContext ctx)
        {
            if (SecureMimeType != SecureMimeType.CertsOnly)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                ContentObject.DecodeTo(memory);
                memory.Position = 0;

                ctx.Import(memory);
            }
        }
        /// <summary>
        /// Import the certificates contained in the content.
        /// </summary>
        /// <param name="ctx">The S/MIME context to import certificates into.</param>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header does not support decryption.
        /// </exception>
        public void Import(SecureMimeContext ctx)
        {
            // FIXME: find out what exceptions BouncyCastle can throw...
            if (SecureMimeType != SecureMimeType.CertsOnly)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryStream()) {
                ContentObject.WriteTo(memory);
                memory.Position = 0;

                ctx.Import(memory);
            }
        }
        /// <summary>
        /// Decrypt using the specified <see cref="CryptographyContext"/>.
        /// </summary>
        /// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns>
        /// <param name="ctx">The S/MIME context to use for decrypting.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header does not support decryption.
        /// </exception>
        public MimeEntity Decrypt(SecureMimeContext ctx)
        {
            // FIXME: find out what exceptions BouncyCastle can throw...
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (SecureMimeType != SecureMimeType.EnvelopedData)
            {
                throw new InvalidOperationException();
            }

            IList <IDigitalSignature> signatures;

            return(Decrypt(ctx, out signatures));
        }
Exemple #12
0
        public SystemSecuritySigner(DkimSignatureAlgorithm algorithm, AsymmetricAlgorithm key)
        {
            rsa = key as RSACryptoServiceProvider;

            switch (algorithm)
            {
            case DkimSignatureAlgorithm.RsaSha256:
                oid           = SecureMimeContext.GetDigestOid(DigestAlgorithm.Sha256);
                AlgorithmName = "RSASHA256";
                hash          = SHA256.Create();
                break;

            default:
                oid           = SecureMimeContext.GetDigestOid(DigestAlgorithm.Sha1);
                AlgorithmName = "RSASHA1";
                hash          = SHA1.Create();
                break;
            }
        }
Exemple #13
0
        /// <summary>
        /// Decrypt the enveloped-data.
        /// </summary>
        /// <remarks>
        /// Decrypts the enveloped-data using the specified <see cref="SecureMimeContext"/>.
        /// </remarks>
        /// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns>
        /// <param name="ctx">The S/MIME context to use for decrypting.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "enveloped-data".
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was cancelled via the cancellation token.
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public MimeEntity Decrypt(SecureMimeContext ctx, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (SecureMimeType != SecureMimeType.EnvelopedData && SecureMimeType != SecureMimeType.Unknown)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                Content.DecodeTo(memory);
                memory.Position = 0;

                return(ctx.Decrypt(memory, cancellationToken));
            }
        }
Exemple #14
0
        /// <summary>
        /// Import the certificates contained in the application/pkcs7-mime content.
        /// </summary>
        /// <remarks>
        /// Imports the certificates contained in the application/pkcs7-mime content.
        /// </remarks>
        /// <param name="ctx">The S/MIME context to import certificates into.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "certs-only".
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public void Import(SecureMimeContext ctx)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (SecureMimeType != SecureMimeType.CertsOnly && SecureMimeType != SecureMimeType.Unknown)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                Content.DecodeTo(memory);
                memory.Position = 0;

                ctx.Import(memory);
            }
        }
Exemple #15
0
        /// <summary>
        /// Verifies the signed-data and returns the unencapsulated <see cref="MimeKit.MimeEntity"/>.
        /// </summary>
        /// <remarks>
        /// Verifies the signed-data and returns the unencapsulated <see cref="MimeKit.MimeEntity"/>.
        /// </remarks>
        /// <returns>The list of digital signatures.</returns>
        /// <param name="ctx">The S/MIME context to use for verifying the signature.</param>
        /// <param name="entity">The unencapsulated entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "signed-data".
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public DigitalSignatureCollection Verify(SecureMimeContext ctx, out MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (SecureMimeType != SecureMimeType.SignedData)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                ContentObject.DecodeTo(memory);
                memory.Position = 0;

                return(ctx.Verify(memory, out entity));
            }
        }
Exemple #16
0
        /// <summary>
        /// Decrypts the content.
        /// </summary>
        /// <remarks>
        /// Decrypts the content using the specified <see cref="SecureMimeContext"/>.
        /// </remarks>
        /// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns>
        /// <param name="ctx">The S/MIME context to use for decrypting.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "enveloped-data".
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public MimeEntity Decrypt(SecureMimeContext ctx)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (SecureMimeType != SecureMimeType.EnvelopedData)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                ContentObject.DecodeTo(memory);
                memory.Position = 0;

                return(ctx.Decrypt(memory));
            }
        }
Exemple #17
0
        /// <summary>
        /// Verify the signed-data and return the unencapsulated <see cref="MimeKit.MimeEntity"/>.
        /// </summary>
        /// <remarks>
        /// Verifies the signed-data and returns the unencapsulated <see cref="MimeKit.MimeEntity"/>.
        /// </remarks>
        /// <returns>The list of digital signatures.</returns>
        /// <param name="ctx">The S/MIME context to use for verifying the signature.</param>
        /// <param name="entity">The unencapsulated entity.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "signed-data".
        /// </exception>
        /// <exception cref="System.FormatException">
        /// The extracted content could not be parsed as a MIME entity.
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was cancelled via the cancellation token.
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public DigitalSignatureCollection Verify(SecureMimeContext ctx, out MimeEntity entity, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (SecureMimeType != SecureMimeType.SignedData && SecureMimeType != SecureMimeType.Unknown)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                Content.DecodeTo(memory);
                memory.Position = 0;

                return(ctx.Verify(memory, out entity, cancellationToken));
            }
        }
Exemple #18
0
        /// <summary>
        /// Decompress the compressed-data.
        /// </summary>
        /// <remarks>
        /// Decompresses the compressed-data using the specified <see cref="SecureMimeContext"/>.
        /// </remarks>
        /// <returns>The decompressed <see cref="MimeKit.MimeEntity"/>.</returns>
        /// <param name="ctx">The S/MIME context to use for decompressing.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header is not "compressed-data".
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public MimeEntity Decompress(SecureMimeContext ctx)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            if (SecureMimeType != SecureMimeType.CompressedData && SecureMimeType != SecureMimeType.Unknown)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryBlockStream()) {
                Content.DecodeTo(memory);
                memory.Position = 0;

                return(ctx.Decompress(memory));
            }
        }
        /// <summary>
        /// Decrypt using the specified <see cref="CryptographyContext"/>.
        /// </summary>
        /// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns>
        /// <param name="ctx">The S/MIME context to use for decrypting.</param>
        /// <param name="signatures">The list of digital signatures for this application/pkcs7-mime part.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="ctx"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The "smime-type" parameter on the Content-Type header does not support decryption.
        /// </exception>
        public MimeEntity Decrypt(SecureMimeContext ctx, out IList <IDigitalSignature> signatures)
        {
            // FIXME: find out what exceptions BouncyCastle can throw...
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (SecureMimeType != SecureMimeType.EnvelopedData)
            {
                throw new InvalidOperationException();
            }

            using (var memory = new MemoryStream()) {
                ContentObject.DecodeTo(memory);
                memory.Position = 0;

                return(ctx.Decrypt(memory, out signatures));
            }
        }
Exemple #20
0
        /// <summary>
        /// Compresses the specified entity.
        /// </summary>
        /// <remarks>
        /// <para>Compresses the specified entity using the specified <see cref="SecureMimeContext"/>.</para>
        /// <para>It should be noted that this feature is not supported by most mail clients,
        /// even among those that support S/MIME.</para>
        /// </remarks>
        /// <returns>The compressed entity.</returns>
        /// <param name="ctx">The S/MIME context to use for compressing.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime Compress(SecureMimeContext ctx, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            using (var memory = new MemoryBlockStream()) {
                var options = FormatOptions.Default.Clone();
                options.NewLineFormat = NewLineFormat.Dos;

                entity.WriteTo(options, memory);
                memory.Position = 0;

                return(ctx.Compress(memory));
            }
        }
Exemple #21
0
        /// <summary>
        /// Cryptographically signs and encrypts the specified entity.
        /// </summary>
        /// <remarks>
        /// Cryptographically signs entity using the supplied signer and then
        /// encrypts the result to the specified recipients.
        /// </remarks>
        /// <returns>The signed and encrypted entity.</returns>
        /// <param name="ctx">The S/MIME context to use for signing and encrypting.</param>
        /// <param name="signer">The signer.</param>
        /// <param name="recipients">The recipients.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="signer"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="recipients"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime SignAndEncrypt(SecureMimeContext ctx, CmsSigner signer, CmsRecipientCollection recipients, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (signer == null)
            {
                throw new ArgumentNullException("signer");
            }

            if (recipients == null)
            {
                throw new ArgumentNullException("recipients");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            return(Encrypt(ctx, recipients, MultipartSigned.Create(ctx, signer, entity)));
        }
Exemple #22
0
        /// <summary>
        /// Cryptographically signs and encrypts the specified entity.
        /// </summary>
        /// <remarks>
        /// Cryptographically signs entity using the supplied signer and then
        /// encrypts the result to the specified recipients.
        /// </remarks>
        /// <returns>The signed and encrypted entity.</returns>
        /// <param name="ctx">The S/MIME context to use for signing and encrypting.</param>
        /// <param name="signer">The signer.</param>
        /// <param name="digestAlgo">The digest algorithm to use for signing.</param>
        /// <param name="recipients">The recipients.</param>
        /// <param name="entity">The entity.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="ctx"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="signer"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="recipients"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="entity"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="CertificateNotFoundException">
        /// <para>A signing certificate could not be found for <paramref name="signer"/>.</para>
        /// <para>-or-</para>
        /// <para>A certificate could not be found for one or more of the <paramref name="recipients"/>.</para>
        /// </exception>
        /// <exception cref="Org.BouncyCastle.Cms.CmsException">
        /// An error occurred in the cryptographic message syntax subsystem.
        /// </exception>
        public static ApplicationPkcs7Mime SignAndEncrypt(SecureMimeContext ctx, MailboxAddress signer, DigestAlgorithm digestAlgo, IEnumerable <MailboxAddress> recipients, MimeEntity entity)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            if (signer == null)
            {
                throw new ArgumentNullException("signer");
            }

            if (recipients == null)
            {
                throw new ArgumentNullException("recipients");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            return(Encrypt(ctx, recipients, MultipartSigned.Create(ctx, signer, digestAlgo, entity)));
        }
		/// <summary>
		/// Encrypts the specified entity.
		/// </summary>
		/// <remarks>
		/// Encrypts the entity to the specified recipients using the supplied <see cref="SecureMimeContext"/>.
		/// </remarks>
		/// <returns>The encrypted entity.</returns>
		/// <param name="ctx">The S/MIME context to use for encrypting.</param>
		/// <param name="recipients">The recipients.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="recipients"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime Encrypt (SecureMimeContext ctx, CmsRecipientCollection recipients, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException (nameof (ctx));

			if (recipients == null)
				throw new ArgumentNullException (nameof (recipients));

			if (entity == null)
				throw new ArgumentNullException (nameof (entity));

			using (var memory = new MemoryBlockStream ()) {
				var options = FormatOptions.CloneDefault ();
				options.NewLineFormat = NewLineFormat.Dos;

				entity.WriteTo (options, memory);
				memory.Position = 0;

				return ctx.Encrypt (recipients, memory);
			}
		}
		/// <summary>
		/// Compresses the specified entity.
		/// </summary>
		/// <remarks>
		/// <para>Compresses the specified entity using the specified <see cref="SecureMimeContext"/>.</para>
		/// <para>It should be noted that this feature is not supported by most mail clients,
		/// even among those that support S/MIME.</para>
		/// </remarks>
		/// <returns>The compressed entity.</returns>
		/// <param name="ctx">The S/MIME context to use for compressing.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime Compress (SecureMimeContext ctx, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (entity == null)
				throw new ArgumentNullException ("entity");

			using (var memory = new MemoryBlockStream ()) {
				var options = FormatOptions.CloneDefault ();
				options.NewLineFormat = NewLineFormat.Dos;

				entity.WriteTo (options, memory);
				memory.Position = 0;

				return ctx.Compress (memory);
			}
		}
		/// <summary>
		/// Cryptographically signs and encrypts the specified entity.
		/// </summary>
		/// <remarks>
		/// Cryptographically signs entity using the supplied signer and then
		/// encrypts the result to the specified recipients.
		/// </remarks>
		/// <returns>The signed and encrypted entity.</returns>
		/// <param name="ctx">The S/MIME context to use for signing and encrypting.</param>
		/// <param name="signer">The signer.</param>
		/// <param name="digestAlgo">The digest algorithm to use for signing.</param>
		/// <param name="recipients">The recipients.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="signer"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="recipients"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="CertificateNotFoundException">
		/// <para>A signing certificate could not be found for <paramref name="signer"/>.</para>
		/// <para>-or-</para>
		/// <para>A certificate could not be found for one or more of the <paramref name="recipients"/>.</para>
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime SignAndEncrypt (SecureMimeContext ctx, MailboxAddress signer, DigestAlgorithm digestAlgo, IEnumerable<MailboxAddress> recipients, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (signer == null)
				throw new ArgumentNullException ("signer");

			if (recipients == null)
				throw new ArgumentNullException ("recipients");

			if (entity == null)
				throw new ArgumentNullException ("entity");

			return Encrypt (ctx, recipients, MultipartSigned.Create (ctx, signer, digestAlgo, entity));
		}
		/// <summary>
		/// Cryptographically signs and encrypts the specified entity.
		/// </summary>
		/// <remarks>
		/// Cryptographically signs entity using the supplied signer and then
		/// encrypts the result to the specified recipients.
		/// </remarks>
		/// <returns>The signed and encrypted entity.</returns>
		/// <param name="ctx">The S/MIME context to use for signing and encrypting.</param>
		/// <param name="signer">The signer.</param>
		/// <param name="recipients">The recipients.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="signer"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="recipients"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime SignAndEncrypt (SecureMimeContext ctx, CmsSigner signer, CmsRecipientCollection recipients, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (signer == null)
				throw new ArgumentNullException ("signer");

			if (recipients == null)
				throw new ArgumentNullException ("recipients");

			if (entity == null)
				throw new ArgumentNullException ("entity");

			return Encrypt (ctx, recipients, MultipartSigned.Create (ctx, signer, entity));
		}
		/// <summary>
		/// Cryptographically signs the specified entity.
		/// </summary>
		/// <remarks>
		/// <para>Signs the entity using the supplied signer, digest algorithm and <see cref="SecureMimeContext"/>.</para>
		/// <para>For better interoperability with other mail clients, you should use
		/// <see cref="MultipartSigned.Create(SecureMimeContext, CmsSigner, MimeEntity)"/>
		/// instead as the multipart/signed format is supported among a much larger
		/// subset of mail client software.</para>
		/// </remarks>
		/// <returns>The signed entity.</returns>
		/// <param name="ctx">The S/MIME context to use for signing.</param>
		/// <param name="signer">The signer.</param>
		/// <param name="digestAlgo">The digest algorithm to use for signing.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="signer"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="CertificateNotFoundException">
		/// A signing certificate could not be found for <paramref name="signer"/>.
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime Sign (SecureMimeContext ctx, MailboxAddress signer, DigestAlgorithm digestAlgo, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (signer == null)
				throw new ArgumentNullException ("signer");

			if (entity == null)
				throw new ArgumentNullException ("entity");

			using (var memory = new MemoryBlockStream ()) {
				var options = FormatOptions.CloneDefault ();
				options.NewLineFormat = NewLineFormat.Dos;

				entity.WriteTo (options, memory);
				memory.Position = 0;

				return ctx.EncapsulatedSign (signer, digestAlgo, memory);
			}
		}
		/// <summary>
		/// Cryptographically signs the specified entity.
		/// </summary>
		/// <remarks>
		/// <para>Signs the entity using the supplied signer and <see cref="SecureMimeContext"/>.</para>
		/// <para>For better interoperability with other mail clients, you should use
		/// <see cref="MultipartSigned.Create(SecureMimeContext, CmsSigner, MimeEntity)"/>
		/// instead as the multipart/signed format is supported among a much larger
		/// subset of mail client software.</para>
		/// </remarks>
		/// <returns>The signed entity.</returns>
		/// <param name="ctx">The S/MIME context to use for signing.</param>
		/// <param name="signer">The signer.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="signer"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime Sign (SecureMimeContext ctx, CmsSigner signer, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException (nameof (ctx));

			if (signer == null)
				throw new ArgumentNullException (nameof (signer));

			if (entity == null)
				throw new ArgumentNullException (nameof (entity));

			using (var memory = new MemoryBlockStream ()) {
				var options = FormatOptions.CloneDefault ();
				options.NewLineFormat = NewLineFormat.Dos;

				entity.WriteTo (options, memory);
				memory.Position = 0;

				return ctx.EncapsulatedSign (signer, memory);
			}
		}
		/// <summary>
		/// Imports the certificates contained in the content.
		/// </summary>
		/// <remarks>
		/// Imports the certificates contained in the content.
		/// </remarks>
		/// <param name="ctx">The S/MIME context to import certificates into.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <paramref name="ctx"/> is <c>null</c>.
		/// </exception>
		/// <exception cref="System.InvalidOperationException">
		/// The "smime-type" parameter on the Content-Type header is not "certs-only".
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public void Import (SecureMimeContext ctx)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (SecureMimeType != SecureMimeType.CertsOnly)
				throw new InvalidOperationException ();

			using (var memory = new MemoryBlockStream ()) {
				ContentObject.DecodeTo (memory);
				memory.Position = 0;

				ctx.Import (memory);
			}
		}
Exemple #30
0
		/// <summary>
		/// Creates a new <see cref="MultipartSigned"/>.
		/// </summary>
		/// <remarks>
		/// Cryptographically signs the entity using the supplied signer in order
		/// to generate a detached signature and then adds the entity along with
		/// the detached signature data to a new multipart/signed part.
		/// </remarks>
		/// <returns>A new <see cref="MultipartSigned"/> instance.</returns>
		/// <param name="ctx">The S/MIME context to use for signing.</param>
		/// <param name="signer">The signer.</param>
		/// <param name="entity">The entity to sign.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="signer"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static MultipartSigned Create (SecureMimeContext ctx, CmsSigner signer, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (signer == null)
				throw new ArgumentNullException ("signer");

			if (entity == null)
				throw new ArgumentNullException ("entity");

			PrepareEntityForSigning (entity);

			using (var memory = new MemoryBlockStream ()) {
				using (var filtered = new FilteredStream (memory)) {
					// Note: see rfc3156, section 3 - second note
					filtered.Add (new ArmoredFromFilter ());

					// Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156)
					filtered.Add (new TrailingWhitespaceFilter ());

					// Note: see rfc2015 or rfc3156, section 5.1
					filtered.Add (new Unix2DosFilter ());

					entity.WriteTo (filtered);
					filtered.Flush ();
				}

				memory.Position = 0;

				// Note: we need to parse the modified entity structure to preserve any modifications
				var parser = new MimeParser (memory, MimeFormat.Entity);
				var parsed = parser.ParseEntity ();
				memory.Position = 0;

				// sign the cleartext content
				var micalg = ctx.GetDigestAlgorithmName (signer.DigestAlgorithm);
				var signature = ctx.Sign (signer, memory);
				var signed = new MultipartSigned ();

				// set the protocol and micalg Content-Type parameters
				signed.ContentType.Parameters["protocol"] = ctx.SignatureProtocol;
				signed.ContentType.Parameters["micalg"] = micalg;

				// add the modified/parsed entity as our first part
				signed.Add (parsed);

				// add the detached signature as the second part
				signed.Add (signature);

				return signed;
			}
		}
		/// <summary>
		/// Verifies the signed-data and returns the unencapsulated <see cref="MimeKit.MimeEntity"/>.
		/// </summary>
		/// <remarks>
		/// Verifies the signed-data and returns the unencapsulated <see cref="MimeKit.MimeEntity"/>.
		/// </remarks>
		/// <returns>The list of digital signatures.</returns>
		/// <param name="ctx">The S/MIME context to use for verifying the signature.</param>
		/// <param name="entity">The unencapsulated entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <paramref name="ctx"/> is <c>null</c>.
		/// </exception>
		/// <exception cref="System.InvalidOperationException">
		/// The "smime-type" parameter on the Content-Type header is not "signed-data".
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public DigitalSignatureCollection Verify (SecureMimeContext ctx, out MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (SecureMimeType != SecureMimeType.SignedData)
				throw new InvalidOperationException ();

			using (var memory = new MemoryBlockStream ()) {
				ContentObject.DecodeTo (memory);
				memory.Position = 0;

				return ctx.Verify (memory, out entity);
			}
		}
		/// <summary>
		/// Encrypts the specified entity.
		/// </summary>
		/// <remarks>
		/// Encrypts the entity to the specified recipients using the supplied <see cref="SecureMimeContext"/>.
		/// </remarks>
		/// <returns>The encrypted entity.</returns>
		/// <param name="ctx">The S/MIME context to use for encrypting.</param>
		/// <param name="recipients">The recipients.</param>
		/// <param name="entity">The entity.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <para><paramref name="ctx"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="recipients"/> is <c>null</c>.</para>
		/// <para>-or-</para>
		/// <para><paramref name="entity"/> is <c>null</c>.</para>
		/// </exception>
		/// <exception cref="System.ArgumentException">
		/// Valid certificates could not be found for one or more of the <paramref name="recipients"/>.
		/// </exception>
		/// <exception cref="CertificateNotFoundException">
		/// A certificate could not be found for one or more of the <paramref name="recipients"/>.
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public static ApplicationPkcs7Mime Encrypt (SecureMimeContext ctx, IEnumerable<MailboxAddress> recipients, MimeEntity entity)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (recipients == null)
				throw new ArgumentNullException ("recipients");

			if (entity == null)
				throw new ArgumentNullException ("entity");

			using (var memory = new MemoryBlockStream ()) {
				var options = FormatOptions.CloneDefault ();
				options.NewLineFormat = NewLineFormat.Dos;

				entity.WriteTo (options, memory);
				memory.Position = 0;

				return (ApplicationPkcs7Mime) ctx.Encrypt (recipients, memory);
			}
		}
		/// <summary>
		/// Decrypts the content.
		/// </summary>
		/// <remarks>
		/// Decrypts the content using the specified <see cref="SecureMimeContext"/>.
		/// </remarks>
		/// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns>
		/// <param name="ctx">The S/MIME context to use for decrypting.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <paramref name="ctx"/> is <c>null</c>.
		/// </exception>
		/// <exception cref="System.InvalidOperationException">
		/// The "smime-type" parameter on the Content-Type header is not "enveloped-data".
		/// </exception>
		/// <exception cref="Org.BouncyCastle.Cms.CmsException">
		/// An error occurred in the cryptographic message syntax subsystem.
		/// </exception>
		public MimeEntity Decrypt (SecureMimeContext ctx)
		{
			if (ctx == null)
				throw new ArgumentNullException ("ctx");

			if (SecureMimeType != SecureMimeType.EnvelopedData)
				throw new InvalidOperationException ();

			using (var memory = new MemoryBlockStream ()) {
				ContentObject.DecodeTo (memory);
				memory.Position = 0;

				return ctx.Decrypt (memory);
			}
		}