在MimeKit上签名和加密

时间:2015-06-22 15:26:12

标签: mimekit

我被要求向我们的客户发送签名和加密的邮件,但是,这是我第一次与签名和加密的斗争(我想强调这一点)。

我尝试过OpaqueMail和MimeKit。 因为我真的不太了解OpaqueMail并且我有自己的客户来检索电子邮件,所以我发现了更好的理解和实现MimeKit。

我知道这是我在以下几行中所做的基本实现,但它只是第一次与它接触而只是一个测试。我可以发送带有加密正文的签名电子邮件,问题附带附件(我们只是发送带有附件文件的空体,来自数据库)。

try
    {
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);

            X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "senderEmail@something.com", false); //TODO Change to true after test
            X509Certificate2 senderCertificate = collection[0];

            store = new X509Store(StoreName.AddressBook, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);

            collection = store.Certificates.Find(X509FindType.FindBySubjectName, "recipientEmail@something.com", false); //TODO Change to true after test
            X509Certificate2 recipientCertificate = collection[0];

            MimeMessage mimeMessage = new MimeMessage
            {
                Date = DateTime.Now,
            };

            mimeMessage.From.Add(
                new SecureMailboxAddress(
                    "senderEmail@gmail.com",
                    "senderEmail@gmail.com",
                    senderCertificate.Thumbprint));

            mimeMessage.To.Add(
                new SecureMailboxAddress(
                    "recipientEmail@gmail.com",
                    "recipientEmail@gmail.com",
                    recipientCertificate.Thumbprint));

            mimeMessage.Subject = "S/MIME Test";

            using (Stream stream = "TestAttachmentFile".ToStream())
            {
                //Attachment
                MimePart attachment = new MimePart(new ContentType("text", "plain"))
                                      {
                                          ContentTransferEncoding =
                                              ContentEncoding.Base64,
                                          ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
                                          FileName = "TestAttachmentFileName.txt",
                                          ContentObject = new ContentObject(stream)
                                      };

                Multipart multipart = new Multipart("mixed") { attachment};

                mimeMessage.Body = multipart;

                //Sign / Encryption
                CmsSigner signer = new CmsSigner(senderCertificate);

                CmsRecipientCollection colle = new CmsRecipientCollection();
                X509Certificate bountyRecipientCertificate = DotNetUtilities.FromX509Certificate (recipientCertificate)

                CmsRecipient recipient = new CmsRecipient(bountyRecipientCertificate);
                colle.Add(recipient);

                using (var ctx = new MySecureMimeContext ()) 
                {
                      var signed = MultipartSigned.Create (ctx, signer, mimeMessage.Body);        
                      var encrypted = ApplicationPkcs7Mime.Encrypt (ctx, colle, signed);           
                      mimeMessage.Body = MultipartSigned.Create (ctx, signer, encrypted);
                }

                //Sending
                using (SmtpClient smtpClient = InitSmtpClient(
                    "mail.smtp.com",
                    465,
                    "sender@something.com",
                    "Pwd",
                    true))
                {
                    smtpClient.Send(mimeMessage);
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

这里有问题:

签名和正文加密有效。但是当我尝试添加一个附件时,我可以打开它但总是出现BOM()我可以看到附件但是thunderbird并没有告诉我它是一个附件,它就像电子邮件的正文一样。我不知道这是否是我实施的ToStream()的问题。此外,Thunderbird无法显示正确的德语字符(ÜüÖöÄäßß),也不能显示西班牙语<

编辑MimeKit.Decryption方法也很好用,而且我得到了没有BOM的消息的正确编码,附件就在那里。对于Thunderbird客户来说,这可能是一个问题。

与SecureMimeContext相关,我们正在使用HanaDB,我们希望将证书存储在那里,检索并使用它们,但我无法找到IX509CertificateDatabase的正确转换,所以,暂时使用WindowsStore。 / em>的

编辑,我解决数据库创建WindowsSecureMimeContext并重写导入以从数据库获取证书的问题。又快又脏。

编辑2,这很难实现,因为我们使用DAO模板实现,我已经从SecureMimeContext创建了子类,我查看了WindowsSecureMimeContext以了解方法的确切做法,只需更改代码以适应我们的DAO东西

如何将X509Certificate2转换为X509Certificate(BouncyCastle),参数CmsRecipient?

EDIT,DotNetUtilities.FromX509Certificate完成了这项工作。

是否可以制作“Tripple Wrap”?签名,加密,再次签名。

编辑,是

using (var ctx = new MySecureMimeContext ()) {
    var signed = MultipartSigned.Create (ctx, signer, mimeMessage.Body);
    var encrypted = ApplicationPkcs7Mime.Encrypt (ctx, colle, signed);
    mimeMessage.Body = MultipartSigned.Create (ctx, signer, encrypted);
}

1 个答案:

答案 0 :(得分:2)

听起来你现在大部分都在使用DotNetUtilities.FromX509Certificate()

看起来你最后一个问题是关于如何“三重换行”。

我建议的是:

using (var ctx = new MySecureMimeContext ()) {
    var encrypted = ApplicationPkcs7Mime.SignAndEncrypt(ctx, signer, colle, mimeMessage.Body);
    mimeMessage.Body = ApplicationPkcs7Mime.Sign (ctx, signer, encrypted);
}

或:

using (var ctx = new MySecureMimeContext ()) {
    var encrypted = ApplicationPkcs7Mime.SignAndEncrypt(ctx, signer, colle, mimeMessage.Body);
    mimeMessage.Body = MultipartSigned.Sign (ctx, signer, encrypted);
}

或:

using (var ctx = new MySecureMimeContext ()) {
    var signed = MultipartSigned.Create (ctx, signer, mimeMessage.Body);
    var encrypted = ApplicationPkcs7Mime.Encrypt (ctx, colle, signed);
    mimeMessage.Body = MultipartSigned.Sign (ctx, signer, encrypted);
}

您可能想要使用其中所有3个选项来查看哪个选项最适合您的客户使用的邮件客户端(Outlook,Thunderbird,Apple Mail?)。

ApplicationPkcs7Mime.SignAndEncrypt()使用application/pkcs7-mime; smime-type=signed-data格式,然后加密与加密multipart/signed不同的格式,不同的客户可以处理不同程度的成功。

使用multipart/signed的一个很好的理由是,即使用户的客户端无法解码S / MIME,电子邮件仍然可以读取,因为它使用分离签名,这意味着邮件的原始文本未封装在二进制签名数据。但是......因为你也在加密,所以它可能没什么区别。

  

与SecureMimeContext相关,我们正在使用HanaDB,我们希望存储   那里的证书,检索和使用它们,但我无法   找到IX509CertificateDatabase的正确转换,所以,使用   WindowsStore暂时。

我建议您查看DefaultSecureMimeContext并实施自己的IX509CertificateDatabase

如果HanaDB是基于SQL的,那么您可能会将SqlCertificateDatabase子类化,这是一个基于SQL的抽象证书数据库实现。您可以查看SqliteCertificateDatabase.csNpgsqlCertificateDatabase.cs(PostgreSQL)以了解如何操作。

或者您可以查看X509CertificateDatabase.cs以了解如何实施通用版本。

除非您实际将证书存储在Windows证书库中,否则我会诚实地避免使用WindowsSecureMimeContext