First you need the public key of the recipient. In this example we will retrieve the public key from AD. Public keys are stored in userCertificate which is a multivalued attribute, so we must pick a valid certificate from all the certificates that may be in the attribute. We’re looking for a certificate which is usable for Secure Email and is currently valid for use (within a 5 minute skew). We will pick the first certificate that meets those criteria.
$RecipientCN='someusername'
$RootDSE = [ADSI]("LDAP://RootDSE")
$SearchForestForPerson = New-Object DirectoryServices.DirectorySearcher
$SearchForestForPerson.SearchRoot = "GC://" + $RootDSE.rootDomainNamingContext
$SearchForestForPerson.SearchScope = "subtree"
$SearchForestForPerson.PropertiesToLoad.Add("distinguishedname") | Out-Null
$SearchForestForPerson.PropertiesToLoad.Add("mail") | Out-Null
$SearchForestForPerson.PropertiesToLoad.Add("usercertificate") | Out-Null
$SearchForestForPerson.Filter = ("(&(objectClass=person)(CN=$RecipientCN))")
$Recipient = $SearchForestForPerson.FindOne()
$ChosenCertificate = $null
$Now = Get-Date
If ($Recipient.Properties.usercertificate -ne $null) {
ForEach ($UserCertificate in $Recipient.Properties.usercertificate) {
$ValidForSecureEmail = $false
$Certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$UserCertificate
$Extensions = $Certificate.Extensions
ForEach ($Extension in $Extensions) {
If ($Extension.EnhancedKeyUsages -ne $null) {
ForEach ($EnhancedKeyUsage in $Extension.EnhancedKeyUsages) {
If ($EnhancedKeyUsage.FriendlyName -eq "Secure Email") {
$ValidForSecureEmail = $true
break
}
}
If ($ValidForSecureEmail) {
break
}
}
}
If ($ValidForSecureEmail) {
If ($Now -gt $Certificate.NotBefore.AddMinutes(-5) -and $Now -lt $Certificate.NotAfter.AddMinutes(5)) {
$ChosenCertificate = $Certificate
}
}
If ($null -ne $ChosenCertificate) {
break
}
}
}
Now that we have a valid certificate, compose and send the email. The forum message at
http://social.msdn.microsoft.com/Forums/en-US/74e4711e-1f66-43a7-9e3b-bc9cfbcd1b73/sending-smime-encrypted-email-using-c provided most of the basis for getting the encryption correct.
Add-Type -assemblyName "System.Security"
$MailClient = New-Object System.Net.Mail.SmtpClient "relay.widgets.com"
$Message = New-Object System.Net.Mail.MailMessage
$Message.To.Add($Recipient.properties.mail.item(0))
$Message.From = "noreply@widgets.com"
$Message.Subject = "Unencrypted subject of the message"
$Body = "Encrypted body of the message"
$MIMEMessage = New-Object system.Text.StringBuilder
$MIMEMessage.AppendLine('Content-Type: text/plain; charset="iso-8859-1"') | Out-Null
$MIMEMessage.AppendLine('Content-Transfer-Encoding: 7bit') | Out-Null
$MIMEMessage.AppendLine() | Out-Null
$MIMEMessage.AppendLine($Body) | Out-Null
[Byte[]] $BodyBytes = [System.Text.Encoding]::ASCII.GetBytes($MIMEMessage.ToString())
$ContentInfo = New-Object System.Security.Cryptography.Pkcs.ContentInfo (,$BodyBytes)
$CMSRecipient = New-Object System.Security.Cryptography.Pkcs.CmsRecipient $ChosenCertificate
$EnvelopedCMS = New-Object System.Security.Cryptography.Pkcs.EnvelopedCms $ContentInfo
$EnvelopedCMS.Encrypt($CMSRecipient)
[Byte[]] $EncryptedBytes = $EnvelopedCMS.Encode()
$MemoryStream = New-Object System.IO.MemoryStream @(,$EncryptedBytes)
$AlternateView = New-Object System.Net.Mail.AlternateView($MemoryStream, "application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m")
$Message.AlternateViews.Add($AlternateView)
$MailClient.Send($Message)
Hi!
ReplyDeleteDo you have a solution to add an attachment into this encrypted email?
If I tried - I lost encryption :-(
Thanks!
regards Tom