Send signed email receive encrypted

In this article we’ll show how to create test certificates or use existing certificate, for sending signed emails. Our recipients will use the public key information from the signed email to encrypt emails they’ll be sending to us. Finally we’ll show how to decrypt those emails.

Create test certificate

We’ll use makecert.exe tool to create certificate in cer format and pvk2pfx.exe tool to convert it to pfx format:


makecert.exe -pe -r -sv Test_Keys.pvk -n "CN=Alice,E=alice2@testdomain.com" -sky exchange Test.cer


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

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.

Create S/MIME signed email

Now we’ll create a signed message using Mail.dll. It is a simple task we just need to load certifcate from disk and use SignWith method:

X509Certificate2 certificate = new X509Certificate2(
    @"c:\Test.pfx";, 
    "", 
    X509KeyStorageFlags.PersistKeySet);

IMail email = Limilabs.Mail.Fluent.Mail.Text("This is a signed message")
    .Subject("This is a signed message")
    .From("alice2@testdomain.com")
    .To("test@testdomain.com")
    .SignWith(certificate)
    .Create();

Send S/MIME signed email

Now we’ll use Smtp class to connect and authenticate to our SMTP server and send the email message:

using(Smtp smtp = new Smtp())
{
    smtp.Connect("smtp.server.com");  // or ConnectSSL for SSL
    smtp.UseBestLogin("user", "password");
 
    smtp.SendMessage(email);                     
 
    smtp.Close();   
}              

Here you can find more details on sending S/MIME signed email.

S/MIME signed email is received

Here’s how the recipient will see the message. Please note that we are using self-signed certificates and this is why we are seeing this warning message.

Next step for the recipient is to mark received certificate as trusted.

The recipient should then add the certificate to the contact list:

As you can see there is a DigitalID assigned to Alice (email sender):

S/MIME encrypted email reply

Finally recipient replies to the message marking the new message to be encrypted.

Receiving S/MIME encrypted email reply

We’ll use IMAP component to download this message. You can use IMAP or POP3 components to download it.

In fact we can see that it is encrypted (we are showing raw eml variable here):

Now we can decrypt the message using the same certificate, we used for signing. Note that we are adding this certificate to SMIMEConfiguration.Certificates collection:

X509Certificate2 certificate = new X509Certificate2(
    @"c:\Text.pfx", 
    "", 
    X509KeyStorageFlags.PersistKeySet);

using(Imap imap = new Imap())
{
    imap.Connect("imap.testdomain.com");
    imap.UseBestLogin("alice2@testdomain.com", "password");

    var eml = imap.GetMessageByNumber(1);

    MailBuilder builder = new MailBuilder();
    builder.SMIMEConfiguration.Certificates.Add(certificate);
    IMail email = builder.CreateFromEml(eml);

    Console.WriteLine(email.IsEncrypted);
    Console.WriteLine(email.Html);
    Console.WriteLine(email.Text);

    imap.Close();
}

You can also find more information about SMIME and Mail.dll here:

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

Update the bound property as the user types

In Silverlight there is no way for 2-way-bound TextBox to update it’s bound property every time user hits a key on the keyboard.

In WPF you could use UpdateSourceTrigger=PropertyChanged, which is not available in Silverlight.

Here’s the nice Silverlight behavior that adds this useful feature to Silverlight:

// Please note that Behavior class is from
// System.Windows.Interactivity assembly that is available
// after you have installed Expression Blend.
// (C:\Program Files\Microsoft SDKs\Expression\Blend\Silverlight\v4.0
//  \Libraries\System.Windows.Interactivity.dll)

public class UpdateOnTextChangedBehavior : Behavior<textBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        this.AssociatedObject.TextChanged +=
                AssociatedObject_TextChanged;
    }

    void AssociatedObject_TextChanged(
        object sender,
        TextChangedEventArgs e)
    {
        BindingExpression binding =
            this.AssociatedObject.GetBindingExpression(
                TextBox.TextProperty);

        if (binding != null)
        {
            binding.UpdateSource();
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        this.AssociatedObject.TextChanged -=
                AssociatedObject_TextChanged;
    }
}

And usage:

<textBox Text="{Binding Title, Mode=TwoWay}">
   <i:Interaction.Behaviors>
      <local:UpdateOnTextChangedBehavior/>
   </i:Interaction.Behaviors>
</textBox>

Imap, Pop3 or Smtp via HTTP or SOCKS proxy

Mail.dll (IMAP, POP3 and SMTP component for .NET) supports following proxy protocols:

  • HTTP
  • SOCKS5
  • SOCKS4a
  • SOCKS4

As a prerequisite you need to add reference to Mail.dll and Proxy.dll libraries in your project. You can find both assemblies in the Mail.dll .NET email component download package. You can also find both assemblies on the .NET tab in Visual Studio’s “Add reference” dialog after installation.

Following sample uses HTTP proxy to access IMAP server:

  1. First it creates proxy with specified type (ProxyType), proxy address and port using proxy factory
  2. Then it connects to IMAP, POP3 or SMTP server via proxy and creates a socket
  3. Finally it attaches socket to IMAP, POP3 or SMTP client
// C# version

ProxyFactory factory = new ProxyFactory();
IProxyClient proxy = factory.CreateProxy(ProxyType.Http, "221.3.154.9", 80);

Socket socket = proxy.Connect("imap.example.org", Imap.DefaultPort);

using (Imap imap = new Imap())
{
    imap.Attach(socket);

    // regular imap code

    imap.Close();
}

' VB.NET version

Dim factory As New ProxyFactory()
Dim proxy As IProxyClient = factory.CreateProxy(ProxyType.Http, "221.3.154.9", 80)

Dim socket As Socket = proxy.Connect("imap.example.org", Imap.DefaultPort)

Using imap As New Imap()
   imap.Attach(socket)

   ' regular imap code

   imap.Close()
End Using

Following sample uses HTTP proxy to access IMAP server over SSL connection. Note that we need to pass IMAP server name again to AttachSSL method for SSL authentication. Please also note that Imap.DefaultSSLPort constant is used.

// C# version

ProxyFactory factory = new ProxyFactory();
IProxyClient proxy = factory.CreateProxy(
   ProxyType.Http, "221.3.154.9", 80);

Socket socket = proxy.Connect("imap.gmail.com", Imap.DefaultSSLPort);

using (Imap imap = new Imap())
{
    imap.AttachSSL(socket, "imap.gmail.com");

    // regular imap code

    imap.Close();
}

' VB.NET version

Dim factory As New ProxyFactory()
Dim proxy As IProxyClient = factory.CreateProxy( _
   ProxyType.Http, "221.3.154.9", 80)

Dim socket As Socket = proxy.Connect("imap.gmail.com", Imap.DefaultSSLPort)

Using imap As New Imap()
   imap.AttachSSL(socket, "imap.gmail.com")

   ' regular imap code

   imap.Close()
End Using

The same code works for Smtp and Pop3 clients: you only need to use different port (Smtp.DefaultPort, Smtp.DefaultSSLPort, Pop3.DefaultPort, Pop3.DefaultSSLPort or any other port your server uses) when creating the proxy, and create appropriate client in ‘using’ line.

Send encrypted email using S/MIME

In this article we’ll show how to send digitally encrypted and signed emails (S/MIME) using Mail.dll .NET email component.

S/MIME (Secure/Multipurpose Internet Mail Extensions) is a standard for public key encryption and signing of MIME data.

S/MIME was originally developed by RSA Data Security Inc. Specification uses Cryptographic Message Syntax, an IETF specification that is identical in most respects with PKCS #7.

S/MIME provides the following cryptographic security services for electronic messaging applications: authentication, message integrity, non-repudiation of origin (using digital signatures), privacy and data security (using encryption). S/MIME specifies the MIME type application/pkcs7-mime (smime-type “enveloped-data”) for data enveloping (encrypting) where the whole (prepared) MIME entity to be enveloped is encrypted and packed into an object which subsequently is inserted into an application/pkcs7-mime MIME entity.

Encryption using MailBuilder

// C#

MailBuilder builder = new MailBuilder();
builder.Html = "<html><body>Encrypted and signed</body></html>";
builder.Subject = "Encrypted and signed";
builder.From.Add(new MailBox("email@in-the-certificate.com", "Alice"));
builder.To.Add(new MailBox("bob@mail.com", "Bob"));
builder.AddAttachment(@"c:\report_2014.pdf");

builder.SignWith(new X509Certificate2("SignCertificate.pfx", ""));
builder.EncryptWith(new X509Certificate2("EncryptCertificate.pfx", ""));
builder.EncryptWith(new X509Certificate2("BobsCertificate.pfx", ""));

IMail email = builder.Create();

' VB.NET

Dim builder As New MailBuilder()
builder.Html = "<html><body>Encrypted and signed</body></html>"
builder.Subject = "Encrypted and signed"
builder.From.Add(New MailBox("email@in-the-certificate.com", "Alice"))
builder.[To].Add(New MailBox("bob@mail.com", "Bob"))
builder.AddAttachment("c:\report_2014.pdf")

builder.SignWith(New X509Certificate2("SignCertificate.pfx", ""))
builder.EncryptWith(New X509Certificate2("EncryptCertificate.pfx", ""))
builder.EncryptWith(New X509Certificate2("BobsCertificate.pfx", ""))

Dim email As IMail = builder.Create()

Remember to encrypt your emails with both sender’s and receiver’s certificates.
This way both parties are able to decrypt such emails.

Encryption using fluent interface

// C# version

IMail email = Mail
    .Html("<html><body>Encrypted and signed</body></html>")
    .Subject("Encrypted and signed")
    .From(new MailBox("email@in-the-certificate.com", "Alice"))
    .To(new MailBox("bob@mail.com", "Bob"))
    .AddAttachment(@"c:\report_2014.pdf")
    .SignWith(new X509Certificate2("SignCertificate.pfx", ""))
    .EncryptWith(new X509Certificate2("EncryptCertificate.pfx", ""))
    .EncryptWith(new X509Certificate2("BobsCertificate.pfx", ""))
    .Create();
' VB.NET

Dim email As IMail = Mail _
	.Html("<html><body>Encrypted and signed</body></html>") _
	.Subject("Encrypted and signed") _
	.From(New MailBox("email@in-the-certificate.com", "Alice")) _
	.To(New MailBox("bob@mail.com", "Bob")) _
	.AddAttachment("c:\report_2014.pdf") _
	.SignWith(New X509Certificate2("SignCertificate.pfx", "")) _
	.EncryptWith(New X509Certificate2("EncryptCertificate.pfx", "")) _
	.EncryptWith(New X509Certificate2("BobsCertificate.pfx", "")) _
	.Create()

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

Create test certificate

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

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.

Sending encrypted email using SMTP

Now we can connect to SMTP server and send the email we recently created:

// C#

using (Smtp client = new Smtp())
{
    client.Connect("smtp.example.com"); // or ConnectSSL
    client.UseBestLogin("user", "password");
    client.SendMessage(email);
    client.Close();
}
' VB.NET

Using client As New Smtp()
	client.Connect("smtp.example.com") ' or ConnectSSL
	client.UseBestLogin("user", "password")
	client.SendMessage(email)
	client.Close()
End Using

By default Mail.dll uses TrippleDES (3-DES) for encryption and SHA-1 alghoritm for signing. You can change those settings and choose different signature and encryption algorithm while sending S/MIME encrypted email message.