Once I made an application that receives digital certificates of type X509 (which implement PKCS # 7) and I can put here some suggestion codes. Some of them are mine and some I set up on the Internet some time ago.
CryptoHelper
/// <summary>
/// Provides methods for performing commonly-used cryptographic tasks
/// </summary>
public static class CryptoHelper
{
/// <summary>
/// Generates a cryptographic signature for a given message
/// </summary>
/// <param name="message">The message to sign</param>
/// <param name="signingCertificate">The certificate to sign the message with</param>
/// <param name="encryptionCertificate">An optional encryption certificate to include along with the signature</param>
/// <returns>The signature for the specified message</returns>
internal static byte[] GetSignature(string message, X509Certificate2 signingCertificate, X509Certificate2 encryptionCertificate)
{
byte[] messageBytes = Encoding.ASCII.GetBytes(message);
SignedCms signedCms = new SignedCms(new ContentInfo(messageBytes), true);
CmsSigner cmsSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signingCertificate);
cmsSigner.IncludeOption = X509IncludeOption.WholeChain;
if (encryptionCertificate != null)
{
cmsSigner.Certificates.Add(encryptionCertificate);
}
Pkcs9SigningTime signingTime = new Pkcs9SigningTime();
cmsSigner.SignedAttributes.Add(signingTime);
signedCms.ComputeSignature(cmsSigner, false);
return signedCms.Encode();
}
/// <summary>
/// Encrypts a message
/// </summary>
/// <param name="message">The message to encrypt</param>
/// <param name="encryptionCertificates">A list of certificates to encrypt the message with</param>
/// <returns>The encrypted message</returns>
internal static byte[] EncryptMessage(string message, X509Certificate2Collection encryptionCertificates)
{
byte[] messageBytes = Encoding.ASCII.GetBytes(message);
EnvelopedCms envelopedCms = new EnvelopedCms(new ContentInfo(messageBytes));
CmsRecipientCollection recipients = new CmsRecipientCollection(SubjectIdentifierType.IssuerAndSerialNumber, encryptionCertificates);
envelopedCms.Encrypt(recipients);
return envelopedCms.Encode();
}
/// <summary>
/// Finds a certificates in the user's local store based on its serial number
/// </summary>
/// <param name="serialNumber">The serial number of the certificate to retrieve</param>
/// <returns>The requested certificate, or null if the certificate is not found</returns>
public static X509Certificate2 FindCertificate(string serialNumber)
{
X509Store localStore = new X509Store(StoreName.My);
localStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
try
{
X509Certificate2Collection matches = localStore.Certificates.Find(
X509FindType.FindBySerialNumber,
serialNumber,
true);
if (matches.Count > 0)
{
return matches[0];
}
else
{
return null;
}
}
finally
{
localStore.Close();
}
}
/// <summary>
/// Finds a certificate in the user's local store based on its subject and usage flags
/// </summary>
/// <param name="subjectDistinguishedName">The subject distinguished name of the certificate</param>
/// <param name="usage">The minimum usage flags the certificate must contain</param>
/// <returns>The requested certificate, or null if the certificate is not found</returns>
public static X509Certificate2 FindCertificate(string subjectDistinguishedName, X509KeyUsageFlags usage)
{
X509Store localStore = new X509Store(StoreName.My);
localStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
try
{
X509Certificate2Collection matches = localStore.Certificates.Find(
X509FindType.FindBySubjectDistinguishedName,
subjectDistinguishedName,
true);
if (matches.Count > 0)
{
foreach (X509Certificate2 cert in matches)
{
foreach (X509Extension extension in cert.Extensions)
{
X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension;
if (usageExtension != null)
{
bool matchesUsageRequirements = ((usage & usageExtension.KeyUsages) == usage);
if (matchesUsageRequirements)
{
return cert;
}
}
}
}
return null;
}
else
{
return null;
}
}
finally
{
localStore.Close();
}
}
}
The following method encrypts an email:
public static void SendCryptographedEmail(ScheduledEmail email, String certificatesDirectory, String attachmentsDirectory, bool attachmentsByLink = true)
{
var message = new SecureMailMessage();
// Look up your signing cert by serial number in your cert store
// X509Certificate2 signingCert = CryptoHelper.FindCertificate("1B37D3");
var signingCert = new X509Certificate2(certificatesDirectory + "\" + email.User.CertificatePath, email.User.CertificatePassword);
// Look up your encryption cert the same way
// X509Certificate2 encryptionCert = CryptoHelper.FindCertificate("22C590");
var encryptionCert = new X509Certificate2(certificatesDirectory + "\" + email.User.CertificatePath, email.User.CertificatePassword);
// Load the recipient's encryption cert from a file.
var recipientCert = new X509Certificate2(certificatesDirectory + "\" + email.User.CertificatePath, email.User.CertificatePassword);
message.From = new SecureMailAddress
(email.User.Email, email.User.Name, encryptionCert, signingCert);
message.To.Add(new SecureMailAddress
(email.Recipient, email.Recipient, recipientCert));
message.Subject = email.Subject;
message.IsBodyHtml = true;
message.IsSigned = true;
message.IsEncrypted = true;
var messageBody = email.Message;
if (attachmentsByLink)
{
messageBody += "<p>Anexos</p>";
foreach (var scheduledEmailAttachment in email.ScheduledEmailAttachments)
{
messageBody += "<p><a href=\"" + BaseUrl() + "Attachments/Download/" +
scheduledEmailAttachment.ScheduledEmailAttachmentId + "\">" +
scheduledEmailAttachment.FileName + "</a></p>";
}
}
else
{
foreach (var scheduledEmailAttachment in email.ScheduledEmailAttachments)
{
byte[] fileBytes =
File.ReadAllBytes(Path.Combine(attachmentsDirectory, scheduledEmailAttachment.FileName));
message.Attachments.Add(
new SecureAttachment(fileBytes,
new SecureContentType(scheduledEmailAttachment.MimeType.ToValue()))
);
}
}
messageBody += "<img src=\"" + BaseUrl() + "/Emails/BrandImage/" + email.ScheduledEmailId + "\" />";
message.Body = messageBody;
// Instantiate a good old-fashioned SmtpClient to send your message
var client = new System.Net.Mail.SmtpClient(email.User.ConfigSMTP.FirstOrDefault().Server, (int)email.User.ConfigSMTP.FirstOrDefault().Port)
{
Credentials = new NetworkCredential(email.User.ConfigSMTP.FirstOrDefault().Username, email.User.ConfigSMTP.FirstOrDefault().Password)
};
// If your SMTP server requires you to authenticate, you need to specify your
// username and password here.
client.Send(message);
}
ScheduledEmail
is a Model MVC, but does not have to be:
public class ScheduledEmail
{
[Key]
public Guid ScheduledEmailId { get; set; }
public Guid UserId { get; set; }
[EmailAddress]
[Required(ErrorMessage = "É necessário um Destinatário")]
public string Recipient { get; set; }
public string Subject { get; set; }
[Required(ErrorMessage = "É necessário um conteúdo para a mensagem")]
public string Message { get; set; }
[Required(ErrorMessage = "É necessário uma data de agendamento para a mensagem")]
// [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm}", ApplyFormatInEditMode = true)]
public DateTime ScheduleDate { get; set; }
public DateTime? SendDate { get; set; }
public string Sending { get; set; }
[NotMapped]
[Display(Name = "Files", ResourceType = typeof(Resources.Language))]
public IEnumerable<HttpPostedFileBase> Files { get; set; }
[Display(Name = "LastModified", ResourceType = typeof(Resources.Language))]
public DateTime LastModified { get; set; }
[Display(Name = "CreatedOn", ResourceType = typeof(Resources.Language))]
public DateTime CreatedOn { get; set; }
public virtual ICollection<ScheduledEmailAttachment> ScheduledEmailAttachments { get; set; }
public virtual User User { get; set; }
}
Articles of Base