Encrypte and Signed email using C# - c#

I how can I have email encrypted and signed ?
Seem that I can either encrypt or signed but not both.
Below is my code
public void SendEncryptedEmail04(
//string SigningCertPath, string EncryptingCertPath,
String sender, String To,
string Subject, string Body,
// string SmtpServer, int SmtpPort, bool HTML)
bool HTML)
{
X509Certificate2 SignCert = new X509Certificate2("D:\\certwithprivatekey.pfx", "password"));
X509Certificate2 EncryptCert = new X509Certificate2("abc#gmail.crt", "");
StringBuilder Message = new StringBuilder();
Message.AppendLine("Content-Type: text/" + ((HTML) ? "html" : "plain") +
"; charset=\"iso-8859-1\"");
Message.AppendLine("Content-Transfer-Encoding: 7bit");
Message.AppendLine();
Message.AppendLine(Body);
byte[] BodyBytes = Encoding.ASCII.GetBytes(Message.ToString());
EnvelopedCms ECms = new EnvelopedCms(new ContentInfo(BodyBytes));
CmsRecipient Recipient = new CmsRecipient(
SubjectIdentifierType.IssuerAndSerialNumber, EncryptCert);
ECms.Encrypt(Recipient);
byte[] EncryptedBytes = ECms.Encode();
SignedCms Cms = new SignedCms(new ContentInfo(EncryptedBytes));
CmsSigner Signer = new CmsSigner
(SubjectIdentifierType.IssuerAndSerialNumber, SignCert);
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MailMessage Msg = new MailMessage();
Msg.To.Add(new MailAddress(To));
Msg.From = new MailAddress(sender);
Msg.Subject = Subject;
//MemoryStream ms = new MemoryStream(EncryptedBytes);
MemoryStream ms = new MemoryStream(SignedBytes);
AlternateView av = new AlternateView(ms,
"application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
//"application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m");
Msg.AlternateViews.Add(av);
SmtpClient smtp = new SmtpClient(emailServer, 25);
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential(sender,"xxxx"));
smtp.Send(Msg);
}
The email received by ThunderBird has the following
However, I changed to
MemoryStream ms = new MemoryStream(EncryptedBytes);
I have
How can I have encrypted and signed ?
Thanks

Related

s/mime signed message cannot be open by outlook

I need to digitally sign email using s/mime. I've created a detached signature for my attachment but outlook can't open it: "Cannot open this item. Your Digital ID name cannot be found by the underlying security system". Certificate is installed on this PC and there is smth need to be tweaked in this code:
const int CHARS_IN_LINE = 64;
StringBuilder message = new StringBuilder();
message.AppendLine("Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\";");
message.AppendLine(" boundary=\"__multipart-signed-boundary__\"");
message.AppendLine("Content-Transfer-Encoding: 7bit");
message.AppendLine("MIME-Version: 1.0");
message.AppendLine("Subject: " + tbMessageSubject.Text);
message.AppendLine();
message.AppendLine("--__multipart-signed-boundary__");
message.AppendLine("Content-Type: text/xml; charset=\"windows - 1251\"");
message.AppendLine("Content-Disposition: attachment; ");
message.AppendLine(" filename=\"" + Path.GetFileName(filename) + "\"");
message.AppendLine("Content-Transfer-Encoding: base64");
message.AppendLine();
var dataToSign = File.ReadAllBytes(filePath);
var base64Data = Convert.ToBase64String(dataToSign, Base64FormattingOptions.None);
var base64DataSb = new StringBuilder(base64Data);
for (int i = CHARS_IN_LINE; i < base64DataSb.Length; i += CHARS_IN_LINE + 2) // \r\n
base64DataSb.Insert(i, "\r\n");
message.AppendLine(base64DataSb.ToString());
message.AppendLine("--__multipart-signed-boundary__");
message.AppendLine("Content-Type: application/pkcs7-signature; name=\"smime.p7m\"");
message.AppendLine("Content-Transfer-Encoding: base64");
message.AppendLine("Content-Disposition: attachment; filename=smime.p7s");
message.AppendLine();
CmsSigner signer = new CmsSigner(clientCert);
SignedCms cms = new SignedCms(new ContentInfo(dataToSign), true);
cms.ComputeSignature(signer);
var signature = cms.Encode();
var base64Signature = Convert.ToBase64String(signature, Base64FormattingOptions.None);
var base64Sb = new StringBuilder(base64Signature);
for (int i = CHARS_IN_LINE; i < base64Sb.Length; i += CHARS_IN_LINE + 2) // \r\n
base64Sb.Insert(i, "\r\n");
message.AppendLine(base64Sb.ToString());
message.AppendLine();
message.AppendLine("--__multipart-signed-boundary__--");
message.AppendLine(".");
var stream = new MemoryStream(Encoding.ASCII.GetBytes(message.ToString()));
MailMessage mail = new MailMessage();
mail.From = new MailAddress(tbEmailFrom.Text);
mail.To.Add(new MailAddress(tbEmailTo.Text));
AlternateView alternateView = new AlternateView(stream, "application/pkcs7-mime; smime-type=signed-data; name=smime.p7m");
alternateView.TransferEncoding = TransferEncoding.SevenBit;
mail.AlternateViews.Add(alternateView);
SmtpClient client = new SmtpClient(host, port);
client.EnableSsl = chbUseSSL.Checked;
client.Send(mail);
Finally, the issue was in specified mediaType in AlternateView, the correct way:
AlternateView alternateView = new AlternateView(stream, "multipart/signed; protocol=\"application/pkcs7-signature\"; boundary=\"__multipart-signed-boundary__\"");
alternateView.TransferEncoding = TransferEncoding.SevenBit;
and thanks to jdweng, I was need to sign not the attachment, but the attachment with it's headers (first __multipart-signed-boundary with attachment)

Send encrypted AND signed mail with .NET MailMessage in c#

I want to send an encrypted and signed mail without using any third-party library.
I'm able to send an email signed or encrypted. But both is not working.
I've tried to send a mail with Thunderbird and looked at the source, but theres nothing that tells the mail is encrypted and signed.
When I use following code
byte[] bodyBytes = Encoding.UTF8.GetBytes("TestBody");
SignedCms cms = new SignedCms(new ContentInfo(bodyBytes), false);
CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signerCert); //X509Certificate2 with private key of sender
cms.ComputeSignature(signer);
byte[] signedBytes = cms.Encode();
EnvelopedCms ecms = new EnvelopedCms(new ContentInfo(signedBytes));
CmsRecipient cmsr = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, encryptCert); //X509Certificate2 with public key of recipient
ecms.Encrypt(cmsr);
byte[] encryptedBytes = ecms.Encode();
MailMessage msg = new MailMessage();
msg.To.Add(new MailAddress(to));
msg.From = new MailAddress(from);
msg.Subject = subject;
MemoryStream ms = new MemoryStream(encryptedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m");
msg.AlternateViews.Add(av);
SmtpClient smtp = new SmtpClient("[smtpServer]", 25);
smtp.Send(msg);
the MailClient just decrypts or checks the signature of the message.. the action which i perform last. How can I tell the Client to do both, decryption and signature check?

How send signed email with attachment

I have method, which sign my email by certificate. This work fine if the line with adding an attachment is commented out.
private static void mailer()
{
MailAddress from = new MailAddress("test#email.cz");
MailAddress to = new MailAddress("test#email.cz");
MailMessage message = new MailMessage(from, to);
message.Subject = "Test subject email";
message.IsBodyHtml = true;
string body = "Content-Type: text/html; charset=utf-8 \r\n Content-Transfer-Encoding: 7bit \r\n\r\n";
body += " Email body signed by certificate ";
byte[] messageData = Encoding.ASCII.GetBytes(body);
SignedCms Cms = new SignedCms(new ContentInfo(messageData));
RSACryptoServiceProvider csp = null;
X509Certificate2 cert = new X509Certificate2(#"C:\TFS\cert_test.p12", "password");
if (cert != null)
{
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
else
{
throw new Exception("Valid certificate was not found");
}
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert);
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MemoryStream signedStream = new MemoryStream(SignedBytes);
AlternateView signedView = new AlternateView(signedStream, "application/pkcs7-mime; smime-type=signed-data; name=sig.p7m");
message.AlternateViews.Add(signedView);
ContentType contentType = new ContentType();
contentType.MediaType = MediaTypeNames.Application.Octet;
contentType.Name = "test.xml";
MemoryStream ms = new MemoryStream(fileData);
ms.Position = 0;
Attachment attachment = new Attachment(ms, contentType);
//message.Attachments.Add(attachment);
SmtpClient client = new SmtpClient("smtp.server.net");
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("smtp.server.net", "password", "user");
try
{
client.Send(message);
}
catch (Exception ex)
{
throw ex;
}
}
But I must add attachments (3 or more) to email. When I add an attachment (just one attachment yet), the email no longer shows as signed and the body of email doesn't show up. I find some samples of my problem, but it useless for me.
I don't encrypt the body of email and an attachment. I need only sign an email by certificate.
Thanks for help.
EDIT: Sorry, I had commented out the line with adding signed AlternateView. Right commented out the line is with adding attachment to the email.

Making Outlook Recognize My Digitally Signed Email

I am using C# .NET 4.0 to send a signed SMTP mail message like so:
private void SendMailMessage(object data)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Subject";
message.IsBodyHtml = true;
message.Body += "Blah blah blah.";
byte[] messageBytes = Encoding.ASCII.GetBytes(message.Body);
SignedCms Cms = new SignedCms(new ContentInfo(messageBytes));
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MemoryStream signedStream = new MemoryStream(SignedBytes);
AlternateView signedView = new AlternateView(signedStream, "application/pkcs7-mime; smime-type=signed-data;name=sig.p7m");
message.AlternateViews.Add(signedView);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
From what I can tell, this "works" in that if view the raw data of the message, I see the alternate view with a big PKCS signature in it. But Outlook doesn't recognize it. The Outlook client normally recognizes signed messages and attempts to validate them and puts a little certificate on the message and all that...
I want that... what am I missing?
Edit: I have made some progress on this on my own, but still having some trouble. Here is what the code looks like now:
private void SendMailMessage(string emailTo)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Special Delivery";
message.IsBodyHtml = false;
string body = "Content-Type: text/plain;charset=\"iso-8859-1\"\nContent-Transfer-Encoding: quoted-printable\n\nHere is some body text!";
byte[] messageBytes = Encoding.ASCII.GetBytes(body);
ContentInfo content = new ContentInfo(messageBytes);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
signedCms.ComputeSignature(Signer);
byte[] signedBytes = signedCms.Encode();
MemoryStream ms = new MemoryStream(signedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
message.AlternateViews.Add(av);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
Of note is that I left message.Body blank this time, only sending the AlternateView. Now, when I send this to an Outlook inbox, I get the padlock icon over my email, the S/MIME doodad kicks in and tries to verify the signer, but fails. The certificate used to sign the email is issued by a publically trusted CA. Edit: That's my fault, the certificate didn't have the "secure email" usage attribute. I'll get a new certificate.
When I send the same email to a Gmail address, I get a blank message with a *.p7m attachment on it that contains a bunch of garbage.
The code that gets this working in Outlook looks like this:
private void SendMailMessage(string emailTo)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Regarding your lottery winnings";
message.IsBodyHtml = false;
string body = "Content-Type: text/plain;charset=\"iso-8859-1\"\nContent-Transfer-Encoding: quoted-printable\n\nBlah blah blah blah blah blah.";
byte[] messageBytes = Encoding.ASCII.GetBytes(body);
ContentInfo content = new ContentInfo(messageBytes);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, emailCert);
signedCms.ComputeSignature(Signer);
byte[] signedBytes = signedCms.Encode();
MemoryStream ms = new MemoryStream(signedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
message.AlternateViews.Add(av);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
Using a valid certificate, of course. Now when I send this email and view it in Outlook, I get the certificate icon on the email, and the S/MIME control successfully validates the signature, and the text shows up just like I want it to without displaying the headers to the user.
Notice that I have to leave message.Body empty. Putting anything in message.Body will break it.

Edit HTML Email template at run time in .net code

I below code is to send email by reading the template html, and it works fine. But now my question is how to pass Salutation customerName from my .net code to the template at run time.
StringBuilder strBlr = new StringBuilder();
string strHTML = string.Empty;
string strTempalteHtmlpath = string.Empty;
//create the mail message
MailMessage mail;
string strFrom = ConfigurationSettings.AppSettings["fromAddressForBT"];
string strSubject = "Thanks for choosing Email contact preference";
mail = new MailMessage(strFrom, customerDetails.EmailId);
mail.Subject = strSubject;
//Read Html Template File Path
strTempalteHtmlpath = Convert.ToString(ConfigurationSettings.AppSettings["TemplatePath"]);
strHTML = File.ReadAllText(strTempalteHtmlpath);
strBlr = strBlr.Append(strHTML);
mail.Body = strBlr.ToString();
mail.IsBodyHtml = true;
//first we create the Plain Text part
AlternateView plainView = AlternateView.CreateAlternateViewFromString(strBlr.ToString(), null, "text/plain");
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(strBlr.ToString(), null, "text/html");
mail.AlternateViews.Add(plainView);
mail.AlternateViews.Add(htmlView);
//send the message
SmtpClient smtpMail = new SmtpClient(ConfigurationSettings.AppSettings["smtpClient"]);
smtpMail.Send(mail);
mail.Dispose();
Thanks.
This is code for sendemail button
StreamReader sr = new StreamReader(Server.MapPath("Sendpage.htm"));
string body = sr.ReadToEnd();
sr.Close();
body = body.Replace("#NameFamily#", txtNameFamily.Text);
body = body.Replace("#Email#", txtEmail.Text);
body = body.Replace("#Tellphone#", txtTellphone.Text);
body = body.Replace("#Text#", txtText.Text);
body = body.Replace("#Date#", DateTime.Now);
string Time = Convert.ToString(DateTime.Now.ToShortTimeString());
body = body.Replace("#Time#", Time);
SendMail("email that you want to send to it", body);
this is sendmail function code:
private void SendMail(string To, string Body)
{
SmtpClient Mailing = new SmtpClient("mail.domain.com");
MailMessage Message = new MailMessage();
Message.From = new MailAddress("mail#domain.com", "Your name or company name");
Message.Subject = "Subject";
Message.SubjectEncoding = Encoding.UTF8;
Message.IsBodyHtml = true;
Message.BodyEncoding = Encoding.UTF8;
Message.Body = Body;
Message.To.Add(new MailAddress(To));
Mailing.UseDefaultCredentials = false;
NetworkCredential MyCredential = new NetworkCredential("mail#domain.com", "password");
Mailing.Credentials = MyCredential; Mailing.Send(Message);
}

Categories

Resources