在MimeKit上签名并加密 [英] Sign and Encrypt on MimeKit

查看:128
本文介绍了在MimeKit上签名并加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须将签名和加密的邮件发送给我们的客户,但是,这是我第一次进行签名和加密的斗争(我想强调这一点).

I was required to send signed and encrypted mails to our customers, however, this is my first time with the fight of sign and encrypt (I want to highlight this point).

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

I have tried with OpaqueMail, and MimeKit. Because I really don't understand deeply OpaqueMail and I have my own clients to retrieve emails, I found far better to understand and implement MimeKit.

我知道这是我在以下几行中所做的最基本的实现,但这只是它的首次接触和测试.我可以发送带有加密主体的签名电子邮件,问题出在附件上(我们只是用数据库发送了带有附件文件的空主体).

I know it is a rudimentary implementation what I did in the following lines, but it is just the first contact with it and just a test. I can send signed emails with encrypted body, the problem come with the attachments (we just sent empty bodies with the attachment file, that comes from a DB).

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(),但是可以看到附件,但是雷鸟并没有告诉我它是附件,就像电子邮件的正文一样.我不知道我实现的ToStream()是否有问题.同样,雷鸟也无法显示西班牙语的正确德语字符(ÜüÖöÄäß)

EDIT MimeKit.Decryption方法也可以很好地工作,并且我也得到了没有BOM的消息的正确编码,并且附件在那里.对于Thunderbird客户来说可能是个问题.

EDIT MimeKit.Decryption methods works pretty well too, and also I get the correct encoding of the message without BOM and the attachment is there. It could be a problem for Thunderbird clients.

与SecureMimeContext有关,我们正在使用HanaDB,并且我们想要在其中存储证书,检索和使用它们,但是我无法找到IX509CertificateDatabase的正确转换,因此暂时使用WindowsStore./em>

Related to SecureMimeContext, we are using HanaDB and we want to store the certificates there, retrieve and use them, but I was not able to find the proper conversion for IX509CertificateDatabase, so, using WindowsStore for the moment.

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

EDIT, I solve the problem with the DB creating a WindowsSecureMimeContext and overriding the import to get the certificates from the DB. Quick and dirty.

编辑2,这很难实现,因为我们使用DAO模板实现,我从SecureMimeContext继承了子类,我查看WindowsSecureMimeContext来了解方法的确切作用,只是更改代码以适合我们的DAO东西

EDIT 2, This was hard to implement, because our implementation with DAO templates, I've made subclass from SecureMimeContext, I look on the WindowsSecureMimeContext to understand what the methods exactly does and just change the code to fit with our DAO stuff.

如何将X509Certificate2转换为X509Certificate(BouncyCastle)以及参数CmsRecipient一样?

编辑,DotNetUtilities.FromX509Certificate完成了该工作.

EDIT, DotNetUtilities.FromX509Certificate did the job.

是否可以制作"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);
}

推荐答案

现在看来,您已经确定要使用DotNetUtilities.FromX509Certificate(),这似乎是您的主要选择.

It sounds like you're most of the way there now that you figured out to use DotNetUtilities.FromX509Certificate().

好像您剩下的最后一个问题是如何三包".

Looks like your last remaining question is about how to "triple-wrap".

我建议这样做:

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);
}

您可能想尝试所有这三个选项,以查看哪个选项最适合您的客户使用的邮件客户端(Outlook,Thunderbird,Apple Mail?).

You might want to play around with all 3 of those options to see which one works best with the mail clients your customers use (Outlook, Thunderbird, Apple Mail?).

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

ApplicationPkcs7Mime.SignAndEncrypt() uses the application/pkcs7-mime; smime-type=signed-data format and then encrypts that which is different from encrypting a multipart/signed and different clients may handle those to various degrees of success.

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

A good reason for using multipart/signed is that the email will still be readable even if the user's client cannot decode S/MIME because it uses a detached signature which means that the original text of the message is not encapsulated within binary signature data. But... since you are encrypting as well, it might not make a difference.

关于SecureMimeContext,我们正在使用HanaDB,并且我们想存储 那里的证书,检索和使用它们,但是我无法 找到IX509CertificateDatabase的正确转换,因此,使用 目前是WindowsStore.

Related to SecureMimeContext, we are using HanaDB and we want to store the certificates there, retrieve and use them, but I was not able to find the proper conversion for IX509CertificateDatabase, so, using WindowsStore for the moment.

我建议您看一下DefaultSecureMimeContext并实现您自己的IX509CertificateDatabase.

I would recommend taking a look at DefaultSecureMimeContext and implementing your own IX509CertificateDatabase.

如果HanaDB是基于SQL的,则可能可以继承SqlCertificateDatabase的子类,该子类是基于SQL的抽象证书数据库实现.您可以看一下SqliteCertificateDatabase.csNpgsqlCertificateDatabase.cs(PostgreSQL)来了解如何做.

If HanaDB is SQL-based, you could probably subclass SqlCertificateDatabase which is an abstract SQL-based certificate database implementation. You can take a look at SqliteCertificateDatabase.cs or NpgsqlCertificateDatabase.cs (PostgreSQL) to get a feel for how to do it.

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

Or you could take a look at X509CertificateDatabase.cs to see how to implement a generic version.

老实说,除非您实际上将证书存储在Windows证书存储区中,否则我将避免使用WindowsSecureMimeContext.

I would honestly avoid WindowsSecureMimeContext unless you are actually storing the certificates in the Windows certificate stores.

这篇关于在MimeKit上签名并加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆