Reputation: 71
I am trying to handle a signed and encrypted e-mail message. More precisely, I want to download an attached Excel file.
To my current knowledge, I own a pfx file (with password), which is an archive containing a private key to decrypt as well as a certificate (public key) to verify the mail sender.
EDIT
With the help of jstedfast I now present a working minimal example.
/* certificates */
X509Certificate2 certificate = new X509Certificate2(
privateKeyFullFileName,
privateKeyPassword,
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Add(certificate);
/* smtp handling */
FindItemsResults<Item> inboxEMails = exchangeService.FindItems(WellKnownFolderName.Inbox, new ItemView(int.MaxValue));
EmailMessage eMail = // find appropriate mail
EmailMessage tmp = EmailMessage.Bind(ExchangeService, eMail.Id, new PropertySet(BasePropertySet.FirstClassProperties));
foreach (Attachment attachment in tmp.Attachments) {
FileAttachment fa = attachment as FileAttachment;
fa.Load();
/* decrypting */
using (MemoryStream rawStream = new MemoryStream(fa.Content)) {
EnvelopedCms envelopedCms = new EnvelopedCms();
envelopedCms.Decode(rawStream.ToArray());
envelopedCms.Decrypt(collection); // <- decrypting with .pfx file
using (MemoryStream decryptedStream = new MemoryStream(envelopedCms.ContentInfo.Content)) {
MimeKit.MimeEntity entity = MimeKit.MimeEntity.Load(decryptedStream);
if (entity is MimeKit.Cryptography.ApplicationPkcs7Mime) {
MimeKit.Cryptography.ApplicationPkcs7Mime p7m = entity as MimeKit.Cryptography.ApplicationPkcs7Mime;
using (MimeKit.Cryptography.TemporarySecureMimeContext ctx = new MimeKit.Cryptography.TemporarySecureMimeContext()) {
Org.BouncyCastle.X509.X509Certificate cert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(certificate);
ctx.Import(cert);
if (p7m.SecureMimeType == MimeKit.Cryptography.SecureMimeType.SignedData) {
MimeKit.MimeEntity extracted;
MimeKit.Cryptography.DigitalSignatureCollection signatures = p7m.Verify(ctx, out extracted);
MimeKit.MimePart part = extracted as MimeKit.MimePart;
if (part != null) {
// TODO
}
MimeKit.Multipart multipart = extracted as MimeKit.Multipart;
if (multipart != null) {
for (int i = 0; i < multipart.Count; ++i) {
MimeKit.MimePart mimePart = multipart.ElementAt(i) as MimeKit.MimePart;
if (mimePart != null && mimePart.IsAttachment) {
using (FileStream outStream = File.Create(/* path + */ mimePart.FileName)) {
try {
mimePart.Content.DecodeTo(outStream);
} catch { }
}
}
}
}
}
}
}
}
}
}
Upvotes: 0
Views: 1623
Reputation: 38618
Starting with the decryptedStream
and assuming that it is an application/pkcs7-mime; smime-type=signed-data
MIME part, you started off correctly, but what you want to do instead of calling Import()
is to call Verify()
instead:
using (var decryptedStream = new MemoryStream (envelopedCms.ContentInfo.Content)) {
var entity = MimeEntity.Load (decryptedStream);
if (entity is ApplicationPkcs7Mime) {
// Note: no need to create a new ApplicationPkcs7Mime part, just cast it!
var p7m = (ApplicationPkcs7Mime) entity;
using (var ctx = new TemporarySecureMimeContext ()) {
// Import the X509Certificate2 into the S/MIME context
var cert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate (certificate);
ctx.Import (cert);
if (p7m.SecureMimeType == SecureMimeType.SignedData) {
// Verify the content *and* extract the original content from the binary envelope
MimeEntity extracted;
var signatures = p7m.Verify (ctx, out extracted);
// Save the Excel content to disk
using (var stream = File.Create ("excel.xls")) {
var part = extracted as MimePart;
part.Content.DecodeTo (stream);
}
}
}
}
}
Upvotes: 1