我被要求向我们的客户发送签名和加密的邮件,但是,这是我第一次与签名和加密的斗争(我想强调这一点)。
我尝试过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);
}
答案 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.cs
或NpgsqlCertificateDatabase.cs
(PostgreSQL)以了解如何操作。
或者您可以查看X509CertificateDatabase.cs
以了解如何实施通用版本。
除非您实际将证书存储在Windows证书库中,否则我会诚实地避免使用WindowsSecureMimeContext
。