2017-07-25 54 views
2

我試圖創建一個PowerShell腳本,將加密消息:如何註冊和使用S/MIME在PowerShell中

  • 建立一個消息
  • 使用我的私人S/MIME證書
  • 註冊信息
  • 加密使用收件人
  • 的S/MIME證書公衆發送已簽名和加密

我的電子郵件消息包括下面的完整腳本,但更改了電子郵件地址,證書名稱等。

使用Internet Explorer將私人證書導入到計算機上。然後在目錄中引用C:\Users\xxx\AppData\Roaming\Microsoft\SystemCertificates\My\Certificates\

問題是,當我使用腳本發送電子郵件時,它正在加密但未簽名。

但是,如果我沒有加密消息,而是在構建存儲器流時包含$SignedMessageBytes(請參閱腳本的第4步中的第一行),那麼電子郵件在發送時會被正確簽名。這表明郵件在加密之前正確地被簽名。

由於某些原因,腳本在加密消息時不會包含簽名。

我該怎麼做才能使郵件加密時包含簽名?

$SMTPServer = "localhost" 
$Recipient = "[email protected]" 
$From = "[email protected]" 
$RecipientCertificatePath = "C:\[email protected]" 
$SignerCertificatePath = "C:\Users\xxx\AppData\Roaming\Microsoft\SystemCertificates\My\Certificates\xxxx" 

Add-Type -assemblyName "System.Security" 
$MailClient = New-Object System.Net.Mail.SmtpClient $SMTPServer 
$Message = New-Object System.Net.Mail.MailMessage 
$Message.To.Add($Recipient) 
$Message.From = $From 
$Body = $null 
$File= get-item -Path "C:\CONTRL__9911837000009_4045399000008_20170704_ELE00207.TXT" 
$Message.Subject = $File.Name 

# STEP 1: Capture Message Body 
$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="+ $file.Name) | Out-Null 
$MIMEMessage.AppendLine("Content-Transfer-Encoding: base64") | Out-Null 
$MIMEMessage.AppendLine("Content-Disposition: attachment; filename="+ $file.Name) | Out-Null 
$MIMEMessage.AppendLine() | Out-Null 

[Byte[]] $binaryData = [System.IO.File]::ReadAllBytes($File) 
[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[]] $MessageBytes = [System.Text.Encoding]::ASCII.GetBytes($MIMEMessage.ToString()) 


# STEP 2: Sign 
$ci = New-Object System.Security.Cryptography.Pkcs.ContentInfo(,$MessageBytes) 
$signedCms = New-Object System.Security.Cryptography.Pkcs.SignedCms($ci) 

$SignerCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($SignerCertificatePath) 
$Signer = New-Object System.Security.Cryptography.Pkcs.CmsSigner($SignerCertificate) 
$timeAttribute = New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime 
$null = $signer.SignedAttributes.Add($timeAttribute) 
$sha2_oid = New-Object System.Security.Cryptography.Oid("2.16.840.1.101.3.4.2.1") 
$Signer.DigestAlgorithm = $sha2_oid 

Write-Host "-----------------------------------------------------" 
Write-Host "Cert friendly name: " $Signer.Certificate.FriendlyName 
Write-Host "Cert subject  : " $Signer.Certificate.Subject 
Write-Host "Cert thumbprint : " $Signer.Certificate.Thumbprint 
Write-Host "Digest algorithm : " $Signer.DigestAlgorithm.FriendlyName 
Write-Host "Sign Time   : " $Signer.SignedAttributes.Values.SigningTime 

$signedCms.ComputeSignature($Signer) 
$SignedMessageBytes = $signedCms.Encode() 


# STEP 3: Encrypt 
$ContentInfo = New-Object System.Security.Cryptography.Pkcs.ContentInfo (,$SignedMessageBytes) 
$CMSRecipient = New-Object System.Security.Cryptography.Pkcs.CmsRecipient $RecipientCertificatePath 
$algo_id = New-Object System.Security.Cryptography.Pkcs.AlgorithmIdentifier("2.16.840.1.101.3.4.1.42") 
$EnvelopedCMS = New-Object System.Security.Cryptography.Pkcs.EnvelopedCms($ContentInfo , $algo_id) 

$EnvelopedCMS.Encrypt($CMSRecipient) 

Write-Host "Key length  : " $EnvelopedCMS.ContentEncryptionAlgorithm.KeyLength 
Write-Host "OID friendly name: " $EnvelopedCMS.ContentEncryptionAlgorithm.Oid.FriendlyName 
Write-Host "OID value  : " $EnvelopedCMS.ContentEncryptionAlgorithm.Oid.Value 
Write-Host "Parameters  : " $EnvelopedCMS.ContentEncryptionAlgorithm.Parameters 

[Byte[]] $EncryptedBytes = $EnvelopedCMS.Encode() 


# STEP 4: Create and send mail 
$MemoryStream = New-Object System.IO.MemoryStream @(,$EncryptedBytes) 
$AlternateView = New-Object System.Net.Mail.AlternateView($MemoryStream, "application/x-pkcs7-mime; smime-type=enveloped-data;name=smime.p7m") 
$Message.AlternateViews.Add($AlternateView) 
$MailClient.Send($Message) 

回答

1

感謝您的基礎工作。

我得到它的工作通過增加一個額外的mime層:

# STEP 3: Encrypt 
$OID = New-Object System.Security.Cryptography.Oid 2.16.840.1.101.3.4.1.42 
$AId = New-Object System.Security.Cryptography.Pkcs.AlgorithmIdentifier ($OID, 256) 

$SignatureBytes = $SignedCMS.Encode() 
$MIMEMessage2 = New-Object system.Text.StringBuilder 
$MIMEMessage2.AppendLine('Content-Type: application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m') | Out-Null 
$MIMEMessage2.AppendLine('Content-Transfer-Encoding: base64') | Out-Null 
$MIMEMessage2.AppendLine() | Out-Null 
$MIMEMessage2.AppendLine([Convert]::ToBase64String($SignedMessageBytes)) | Out-Null 

Byte[]] $BodyBytes = [System.Text.Encoding]::UTF8.GetBytes($MIMEMessage2.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, $AId) 
$EnvelopedCMS.Encrypt($CMSRecipient) 
[Byte[]] $EncryptedBytes = $EnvelopedCMS.Encode() 

我不知道,如果上面的代碼將工作開箱即用,因爲我的變量名可能與你的不同。

上述代碼僅在Outlook2016中測試過。

+0

@abil這太棒了。感謝那。有沒有可能轉換,以便它先加密然後再簽名(而不是簽名然後加密)。我試過了,但是我最終得到了多層的加密和簽名,並且它不起作用。 – gerard

相關問題