Подпишите и зашифруйте на 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);
        }

Ну вот вопросы:

Знак и тело шифрования работает. Но когда я пытаюсь добавить вложение, я могу открыть его, но всегда показываю спецификацию (ï "¿), я вижу вложение, однако thunderbird не говорит мне, что это вложение, оно похоже на текст письма. Я не знаю, если это проблема из ToStream(), который я реализовал. Также Thunderbird не смог показать правильные немецкие символы (ÜüÖöÄäß) ни для испанского -

РЕДАКТИРОВАТЬ MimeKit.Decryption методы тоже работает довольно хорошо, а также я получаю правильную кодировку сообщения без спецификации и вложения есть. Это может быть проблемой для клиентов Thunderbird.


Что касается SecureMimeContext, мы используем HanaDB, и мы хотим хранить там сертификаты, извлекать и использовать их, но я не смог найти правильное преобразование для IX509CertificateDatabase, поэтому в данный момент использую WindowsStore.

РЕДАКТИРОВАТЬ, я решаю проблему с БД, создавая WindowsSecureMimeContext и переопределяя импорт, чтобы получить сертификаты из БД. Быстро и грязно.

РЕДАКТИРОВАТЬ 2, это было трудно реализовать, потому что наша реализация с шаблонами DAO, я сделал подкласс от SecureMimeContext, я смотрю на WindowsSecureMimeContext, чтобы понять, что именно делают методы, и просто изменить код, чтобы он соответствовал нашему DAO.


Как я могу преобразовать из X509Certificate2 в X509Certificate(BouncyCastle), как параметр CmsRecipient?

EDIT, DotNetUtilities.FromX509Сертификат сделал свою работу.


Можно ли сделать "тройное обертывание"? Подпишите, зашифруйте, подпишите снова.

РЕДАКТИРОВАТЬ, Да

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 ответ

Решение

Похоже, что вы сейчас в большинстве случаев, когда вы решили использовать 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);
}

Возможно, вы захотите поэкспериментировать со всеми этими тремя вариантами, чтобы увидеть, какой из них лучше всего работает с почтовыми клиентами, которые используют ваши клиенты (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.cs или же NpgsqlCertificateDatabase.cs (PostgreSQL), чтобы понять, как это сделать.

Или вы могли бы взглянуть на X509CertificateDatabase.cs чтобы увидеть, как реализовать универсальную версию.

Я бы честно избегал WindowsSecureMimeContext если вы на самом деле не храните сертификаты в хранилищах сертификатов Windows.

Другие вопросы по тегам