Email is by-nature not secure. Network administrators can view mail, and it can easily be seen on the wire. In order to protect email, there are many methods out there, (PGP, etc). What I want to address today is encrypting an email message using Asymmetric X.509 Cryptography. What this means is that the sender will have the public key of the recipient. This X.509 certificate is used to encrypt the email message body. All senders will have the same public key. But, by nature of asymmetric cryptography, only the holder of the private key can decrypt the message. So, once something is encrypted with a public key, even the sender cannot decrypt the message. Only the holder of the “other part” of the key (the private key) can decrypt the message.
Now, in order for this to work, a certificate capable of encrypting must be issued. I won’t address that here. So, given the subject of an installed X.509 certificate public key, the following class encrypts and sends the message.
(I actually used this class in a WPF sample application, so it is written with INotifyPropertyChanged events for data binding…but that part of the code is not necessary, obviously.)
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.ComponentModel;
6 using System.Security.Cryptography.X509Certificates;
7 using System.Text;
8 using System.Security.Cryptography.Pkcs;
9 using System.IO;
10 using System.Net.Mail;
11
12 namespace Whatever
13 {
14 public class MailMessage : INotifyPropertyChanged
15 {
16 private string _to;
17 private string _from;
18 private string _subject;
19 private string _body;
20 private string _signingCertSubject;
21 private string _encryptingCertSubject;
22
23 public MailMessage()
24 {
25
26 }
27
28 #region INotifyPropertyChanged Members
29
30 public event PropertyChangedEventHandler PropertyChanged;
31
32 protected void OnPropertyChanged(string propertyName)
33 {
34 if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
35 }
36
37 #endregion
38
39 public string To
40 {
41 get { return _to; }
42 set { _to = value; OnPropertyChanged("To"); }
43 }
44
45 public string From
46 {
47 get { return _from; }
48 set { _from = value; OnPropertyChanged("From"); }
49 }
50
51 public string Subject
52 {
53 get { return _subject; }
54 set { _subject = value; OnPropertyChanged("Subject"); }
55 }
56
57 public string Body
58 {
59 get { return _body; }
60 set { _body = value; OnPropertyChanged("Body"); }
61 }
62
63 public string SigningCertSubject
64 {
65 get { return _signingCertSubject; }
66 set { _signingCertSubject = value; OnPropertyChanged("SigningCertSubject"); }
67 }
68
69 public string EncryptingCertSubject
70 {
71 get { return _encryptingCertSubject; }
72 set { _encryptingCertSubject = value; OnPropertyChanged("EncryptingCertSubject"); }
73 }
74
75 public void Send()
76 {
77 X509Certificate2 signing = null;
78 X509Certificate2 encrypting = null;
79
80 X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
81 store.Open(OpenFlags.ReadOnly);
82 if (!string.IsNullOrEmpty(this.SigningCertSubject))
83 {
84 signing = store
85 .Certificates
86 .Find(X509FindType.FindBySubjectName,
87 this.SigningCertSubject,
88 false)
89 .OfType<X509Certificate2>()
90 .FirstOrDefault();
91 }
92 if (!string.IsNullOrEmpty(this.EncryptingCertSubject))
93 {
94 encrypting = store
95 .Certificates
96 .Find(X509FindType.FindBySubjectName,
97 this.EncryptingCertSubject,
98 false)
99 .OfType<X509Certificate2>()
100 .FirstOrDefault();
101 }
102
103 StringBuilder msg = new StringBuilder();
104 msg.AppendLine("Content-Type: text/plain; charset=\"iso-8859-1\"");
105 msg.AppendLine("Content-Transfer-Encoding: 7bit");
106 msg.AppendLine();
107 msg.AppendLine(this.Body);
108 byte[] buffer = null;
109 if (encrypting != null)
110 {
111 buffer = Encoding.ASCII.GetBytes(msg.ToString());
112 EnvelopedCms cms = new EnvelopedCms(new ContentInfo(buffer));
113 CmsRecipient recip = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, encrypting);
114 cms.Encrypt(recip);
115 buffer = cms.Encode();
116
117 if (signing != null)
118 {
119 SignedCms scms = new SignedCms(new ContentInfo(buffer));
120 CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signing);
121
122 scms.ComputeSignature();
123 buffer = scms.Encode();
124 }
125 }
126 store.Close();
127
128 System.Net.Mail.MailMessage mail = new System.Net.Mail.MailMessage();
129 mail.To.Add(new System.Net.Mail.MailAddress(this.To));
130 mail.From = new System.Net.Mail.MailAddress(this.From);
131 mail.Subject = this.Subject;
132
133 if (buffer != null)
134 {
135 MemoryStream ms = new MemoryStream(buffer);
136 AlternateView v = new AlternateView(ms,
137 "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
138 mail.AlternateViews.Add(v);
139 }
140 else
141 {
142 mail.Body = this.Body;
143 }
144
145 SmtpClient client = new SmtpClient();
146 client.Send(mail);
147 }
148 }
149 }
Now, the recipient of the email (who has the private X.509 key installed) can open this message in Outlook, or other capable email clients. The private key must be accessible to the email client.