我被要求向我们的客户发送签名和加密的邮件,然而,这是我第一次与签名和加密的斗争(我想强调这一点)。
我尝试过使用 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。
编辑,我解决了数据库创建 WindowsSecureMimeContext 并覆盖导入以从数据库获取证书的问题。又快又脏。
编辑 2,这很难实现,因为我们使用 DAO 模板实现,我从 SecureMimeContext 创建了子类,我查看 WindowsSecureMimeContext 以了解这些方法的确切作用,并更改代码以适应我们的 DAO 内容。
我如何将 X509Certificate2 转换为 X509Certificate(BouncyCastle),就像参数 CmsRecipient 一样?
编辑,DotNetUtilities.FromX509Certificate 完成了这项工作。
是否可以制作“三重包裹”?签名,加密,再次签名。
编辑,是的
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);
}