Decrypt S/MIME emails

After you have downloaded S/MIME encrypted email from IMAP or POP3 server you need to parse and decrypt it.

MailBuilder class tries to automatically decrypt emails using StoreName.My certificate store.

Of course, you can explicitly specify certificates that should be used for decryption. You should use MailBuilder.SMIMEConfiguration property for that.

If you use CER or PEM files you can find more information in this article:
Importing private/public keys or certificates in PEM, CER formats.
// C# version

var eml = client.GetMessageByUID(uid);

X509Certificate2 certificate = new X509Certificate2(
   "certificate.pfx", "", X509KeyStorageFlags.PersistKeySet);

MailBuilder builder = new MailBuilder();
builder.SMIMEConfiguration.Certificates.Add(certificate);

IMail decrypted = builder.CreateFromEml(eml);

Console.WriteLine(decrypted.NeedsDecryption);  // outputs false
Console.WriteLine(decrypted.IsEncrypted);      // outputs true

' VB.NET version

Dim eml = client.GetMessageByUID(uid)

Dim certificate As New X509Certificate2("certificate.pfx", "", X509KeyStorageFlags.PersistKeySet)

Dim builder As New MailBuilder()
builder.SMIMEConfiguration.Certificates.Add(certificate)

Dim decrypted As IMail = builder.CreateFromEml(eml)

Console.WriteLine(decrypted.NeedsDecryption)   ' outputs False
Console.WriteLine(decrypted.IsEncrypted);      ' outputs True

IMail.IsEncrypted property returns true for both: S/MIME emails that need to be decrypted, and those that where decrypted.

If you want to instruct MailBuilder not to decrypt emails automatically and decrypt them later, you should set MailBuilder.DecryptAutomatically property to false.

To know if an email needs to decryption use IMail.NeedsDecryption property.

// C# version

var eml = client.GetMessageByUID(uid);

MailBuilder builder = new MailBuilder();
builder.DecryptAutomatically = false;

IMail encrypted = builder.CreateFromEml(eml);

Console.WriteLine(encrypted.NeedsDecryption);   // outputs true
Console.WriteLine(encrypted.IsEncrypted);       // outputs true

X509Certificate2 certificate = new X509Certificate2(
   "certificate.pfx", "", X509KeyStorageFlags.PersistKeySet);

IMail decrypted = mail.Decrypt(certificate);

Console.WriteLine(decrypted.NeedsDecryption);  // outputs false
Console.WriteLine(decrypted.IsEncrypted);      // outputs true

' VB.NET version

Dim eml = client.GetMessageByUID(uid)

Dim builder As New MailBuilder()
builder.DecryptAutomatically = False

Dim encrypted As IMail = builder.CreateFromEml(eml)

Console.WriteLine(decrypted.NeedsDecryption)   ' outputs True
Console.WriteLine(decrypted.IsEncrypted);      ' outputs True

Dim certificate As New X509Certificate2( _
   "certificate.pfx", "", X509KeyStorageFlags.PersistKeySet)

Dim decrypted As IMail = mail.Decrypt(certificate)

Console.WriteLine(decrypted.NeedsDecryption)  ' outputs False
Console.WriteLine(decrypted.IsEncrypted);     ' outputs True

Common errors you may encounter:

  • Please use the PersistKeySet flag when loading from file (new X509Certificate2(_certificatePath, “”, X509KeyStorageFlags.PersistKeySet);) and adding to store
  • “Bad key” exception message means that certificate was not for key exchange – makecert needs an extra parameter to create certificate that can be used for symmetric algorithm key exchange: -sky exchange.
  • “the enveloped data-message does not contain the specified recipient” means that certificate with the private key is not deployed into the current account/local machine personal store, or not in the certificates list
  • “Cannot find object or property.” means that the certificate was found, but there is no private key in it. Consider importing it by double clicking the pfx file (Remember to import all extended properties and place all certificates in Personal store).

You can use following commands in VisualStudio Command Prompt to create test certificate:

makecert.exe -pe -r -sv Test_Keys.pvk -n "CN=John Doe,E=email@in-the-certificate.com" -sky exchange Test.cer

pvk2pfx.exe -pvk Test_Keys.pvk -spc Test.cer -pfx Test.pfx

Tags: , , ,

7 Responses to “Decrypt S/MIME emails”

  1. Send signed email receive encrypted Says:

    […]   « Decrypt S/MIME emails INotifyPropertyChanged with custom targets […]

  2. Adam Corum Says:

    How does it make use of the encryption algorithm. I’ve been trying many different signing and encrypt algorithms and it seems to chew on whatever I give it. I have a requirement to restrict to a specific set of ciphers but I don’t see how I can tell mail dll that.

  3. Limilabs support Says:

    @Adam,

    You need to be more specific than “it seems to chew on whatever I give it”.
    What are you trying to do? Send encrypted email or decrypt the one you have received? Are you getting any exception? Error? From Mail.dll or from your email program?
    Please read this article, if you need to specify SMIME encryption algorithm explicitly.

  4. Adam Corum Says:

    Thanks for the response. By “chewing on it”, I meant that that it would decrypt. I found IMail.GetEnvelopedCms() and IMail.GetSignedCms() methods and am now able to implement the restrictions on unsupported ciphers and signature algorithms to protect my .Decrypt call.

  5. Limilabs support Says:

    @Adam,

    Now I get it. Your solution is correct. IMail.GetEnvelopedCms() is the way to go. I think that it’s also possible for the certificate itself to enforce some of those policies.

  6. Adam Corum Says:

    Hello again,

    Today I’m trying to ascertain what set of things the .IsEncrypted property takes into account. Specifically, does it contain a check for the content type call email.HasContentType(“application/pkcs7-mime”, “smime-type”, “enveloped-data”) ?

  7. Limilabs support Says:

    @Adam,

    Mail.dll recognizes encrypted emails by content-type headers: application/pkcs7-mime or application/x-pkcs7-mime with smime-type set to enveloped-data or enveloped data found inside the actual asn.1 content. IsEncrypted does not actually check for content type as email parsing occurs much earlier.

    Please also note that Mail.dll email component decrypts email messages automatically. For such decrypted messages IsEncrypted will be set to true (NeedsDecryption is false) although decrypted message does not contain application/pkcs7-mime content type any longer.

    email.HasContentType method is most likely an extension method and was not developed by us.

Questions?

Consider using our Q&A forum for asking any questions.