-1

I'm implementing to write a PowerShell script to send a secured email which contains password in it. I've been investigating the good ways to implement, but I cannot find out a proper method.

The scenario is: A person requests a password, the script will automatically generate the password and send it to this person email, this person uses Outlook to open the mail box.

My desire is to force the person using his AD credential to open the email, but to do this, an account runs this script needs to have this person's certificate. Thus, it seems impossible.

My second idea is to create a webpage where password requestors can decrypt the password they received via an email. The webpage requires Single-Sign-On and other tricks to protect the authenticated users who want to logon.

If you have any better ideas, may you help me to sort it out?

SamErde
  • 3,409
  • 3
  • 24
  • 44
Ender
  • 614
  • 3
  • 9
  • 14
  • 2
    Unfortunately, the answer is still "don't send passwords via email." The one possible solution that I can think of is IF you have a secure email solution that provides an API that PowerShell can utilize...then you may be able to accomplish your goal, but not otherwise. – SamErde May 25 '18 at 13:52
  • @SturdyErde I found solution is to use S/MIME to force the requestor using their pincode to open the email. Problem solved! – Ender May 28 '18 at 07:02

2 Answers2

1

Short of encrypting the password in the email, I can't help feeling you're trying to get a level of security out of email that it's just not designed for. You're trusting putting the password in an email, but not trusting who the recipient will be, and trying to add a level of verification to an individual email in Outlook. That sounds pretty flawed to me.

If you're going to setup a web page anyway, why not do it all on the webpage, with user auth done there? Use the email for a 2FA verification layer only, if you need it.

gfkBill
  • 11
  • 1
0
param(
    $sAMAccount,
    $filePath
)

$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=$sAMAccount))") 
$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 ($ChosenCertificate -ne $null) { 
            break 
        } 
    } 
}
$keytab = Get-item -Path $filePath
Add-Type -assemblyName "System.Security" 
$MailClient = New-Object System.Net.Mail.SmtpClient "ip.contoso.se" 
$Message = New-Object System.Net.Mail.MailMessage
$Message.To.Add($Recipient.properties.mail.item(0)) 
$Message.From = "noreply@contoso.se" 
$Message.Subject = "Test Unencrypted subject of the message"

$Body = "This is the password for your service account: p4ssw09rd23!"

$MIMEMessage = New-Object system.Text.StringBuilder 
$MIMEMessage.AppendLine("MIME-Version: 1.0") | Out-Null 
$MIMEMessage.AppendLine("Content-Type: multipart/mixed; boundary=unique-boundary-1") | Out-Null 
$MIMEMessage.AppendLine() | Out-Null
$MIMEMessage.AppendLine("This is a multi-part message in MIME format.") | Out-Null
$MIMEMessage.AppendLine("--unique-boundary-1") | Out-Null
$MIMEMessage.AppendLine("Content-Type: text/plain") | Out-Null
$MIMEMessage.AppendLine("Content-Transfer-Encoding: 7Bit") | Out-Null
$MIMEMessage.AppendLine()|Out-Null
$MIMEMessage.AppendLine($Body) | Out-Null
$MIMEMessage.AppendLine() | Out-Null

$MIMEMessage.AppendLine("--unique-boundary-1") | Out-Null
$MIMEMessage.AppendLine("Content-Type: application/octet-stream; name="+ $keytab.Name) | Out-Null
$MIMEMessage.AppendLine("Content-Transfer-Encoding: base64") | Out-Null
$MIMEMessage.AppendLine("Content-Disposition: attachment; filename="+ $keytab.Name) | Out-Null
$MIMEMessage.AppendLine() | Out-Null

[Byte[]] $binaryData = [System.IO.File]::ReadAllBytes($keytab)
[string] $base64Value = [System.Convert]::ToBase64String($binaryData, 0, $binaryData.Length)
[int] $position = 0
while($position -lt $base64Value.Length)
{
    [int] $chunkSize = 100
    if (($base64Value.Length - ($position + $chunkSize)) -lt 0)
    {
        $chunkSize = $base64Value.Length - $position
    }
$MIMEMessage.AppendLine($base64Value.Substring($position, $chunkSize))|Out-Null
$MIMEMessage.AppendLine()|Out-Null
$position += $chunkSize;
}
$MIMEMessage.AppendLine("--unique-boundary-1--") | 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)
Ender
  • 614
  • 3
  • 9
  • 14