如何在 PowerShell 中使用 S/MIME 对消息进行签名和加密

2024-01-18

我正在尝试创建一个 PowerShell 脚本,该脚本将:

  • 建立消息
  • 使用我的私有 S/MIME 证书对邮件进行签名
  • 使用收件人的 S/MIME 公共证书加密邮件
  • 发送已签名并加密的电子邮件

我已经包含了下面的完整脚本,但更改了电子邮件地址、证书名称等。

私有证书已使用 Internet Explorer 导入到计算机上。然后在目录中引用它C:\Users\xxx\AppData\Roaming\Microsoft\SystemCertificates\My\Certificates\

问题是,当我使用脚本发送电子邮件时,它已被加密但未签名。

但是,如果我不加密消息而是包含$SignedMessageBytes构建内存流时(请参阅脚本步骤 4 中的第一行),电子邮件在发送时已正确签名。这表明消息在加密之前已被正确签名。

由于某种原因,脚本在加密消息时不会包含签名。

我必须做什么才能在加密消息时包含签名?

$SMTPServer = "localhost"
$Recipient = "[email protected] /cdn-cgi/l/email-protection"
$From = "[email protected] /cdn-cgi/l/email-protection"
$RecipientCertificatePath = "C:\[email protected] /cdn-cgi/l/email-protection"
$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)

感谢您的基础工作。

我通过添加一个额外的 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下测试。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 PowerShell 中使用 S/MIME 对消息进行签名和加密 的相关文章

  • 如何在 PowerShell 中获取当前活动/前台窗口

    我知道这可以通过使用 alt tab 轻松完成 但创建此脚本的主要目的是自学一些 PowerShell 基础知识 我正在编写一个脚本 运行时会在 powershell 和当前前台窗口之间切换前台窗口 我读这个问题 https stackov
  • 将大数字转换为字母(然后再转换回来)

    是否有一个术语来描述将大数字存储为字母的想法 例如 假设我有 相对较小的 数字 138201162401719 并且我想将字符数缩小到尽可能少的字符数 我知道这无助于节省磁盘空间 英文字母表中有 26 个字母 但我将它们算作 25 个 因为
  • 如何从 Powershell 访问 COM 对象上的索引属性

    我正在使用 Powershell 通过 COM 与 Windows 7 任务计划程序服务进行通信任务调度2 0接口 http msdn microsoft com en us library aa383600 VS 85 aspx 例如 I
  • 在 SQLite 中加密数据

    如何加密我的数据 就我研究的解决方案而言 有两种方法 使用android提供的算法加密数据 我使用android提供的 Cipher 来加密我的数据 但我在检索大量记录的数据时遇到问题 导致应用程序的性能显着降低 我对整个数据库进行了编码
  • 为什么乘法不适用于 Read-Host 值

    table num Read Host Prompt Enter the table number you want to get printed for i 1 i lt 11 i ans table num i write table
  • 在 DownloadProgressChanged 事件期间从 DownloadFileAsync 对事件处理程序的更新缓慢

    我的问题 我正在编写一个 PowerShell 脚本 在继续执行其他任务之前 该脚本需要从远程 Web 服务器下载几个大文件 我的项目要求之一是显示每次下载的进度 以便最终用户知道发生了什么 对另一个 SO 问题的回复包含一个使用注册事件和
  • 命令提示符 con 的 Powershell 通讯员?

    例如 我想在屏幕上显示输出并将其复制到剪贴板 dir tee con clip 上面的方法不起作用 因为con在 PowerShell 的文件系统中不被识别为控制台 还可能存在以下场景 Get LongLongOutput tee con
  • MCRYPT 的等效加密 - 保留客户端代码

    我正在使用以下代码使用 mcrypt 执行加密
  • Powershell:如何获取从 PsJob 内运行的进程返回的退出代码?

    我在 powershell 中有以下工作 job start job c utils MyToolReturningSomeExitCode cmd ArgumentList JobFile 如何访问返回的退出代码c utils MyToo
  • 在 ruby​​ 中读/写受密码保护和加密的文件

    我想加密一个 ruby 程序将从中加载数据的文件 此外 我需要程序在启动时提示输入密码 该密码将用于解密文件 换句话说 该文件需要加密地驻留在计算机上 只有拥有密码的用户才能运行该应用程序 我已经开始研究 openpgp 但据我了解 这仍然
  • 如何通过在原始文件名前添加序列号来重命名文件?

    伙计们 有谁知道我该怎么做 我试图通过在文件名的开头添加 1 2 3 等按数字顺序列出一些文件 同时保留文件的原始名称 这是我尝试过的代码 nr 1 Dir path C x y deneme Rename Item NewName 0 N
  • 获取 Wi-Fi 配置文件信息

    我使用的是 Windows 8 1 它没有工具 带有 GUI 来管理 wifi 网络配置文件 所以我正在写一篇对我有帮助的文章 我做了一些谷歌搜索并发现托管 Wifi API https managedwifi codeplex com 并
  • 恢复 SQL Server 数据库 - 主密钥未打开

    我必须制作远程 SQL Server 数据库的本地副本 我通过使用 Management Studio 中的 任务 gt 备份 来完成此操作 然后 我在本地恢复了备份 该备份似乎包含了所有内容 表 用户 对称密钥和证书 当我尝试执行需要打开
  • 检查文件是否存在,然后移动它

    我正在尝试在 powershell 中编写几行代码 以检查文件是否到达特定文件夹 如果该文件存在 请将其复制到另一个文件夹 如果该文件不存在 则无需执行任何操作 到目前为止我只有复制部分 cd C Move y C myfolder csv
  • 计算 RSA 128 位密钥长度需要多长时间? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我在网上做了一些研究 似乎表明 RSA 加密的推荐密钥长度是 1024 位 但是我有一个问题 对于今天使用的普通计算机来说 计算 128 位 RSA
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 检测 PowerShell 开关

    我正在用 C 开发 PowerShell cmdlet 并且有 true false switch 语句 我注意到 如果我希望 bool 为 true 我需要指定 SwitchName true 否则我会得到 Missing an argu
  • Android - 在sqlite数据库中存储敏感数据

    我需要将敏感数据存储在 Android 应用程序的 sqlite 数据库中 我如何确定这些数据非常安全 我知道我可以使用密钥加密数据 但是我将该密钥存储在哪里 我也不想要求用户填写密钥 我只是希望它能够自行工作 因为我害怕逆向工程 所以我也
  • 我必须使用什么加密程序来通过 HTTP 协议发送加密的“电子邮件”和“密码”值?

    我正在使用 Ruby on Rails 3 我想通过 HTTP 协议发送 电子邮件 和 密码 值 我知道 我不应该 但我需要 我需要从发送用户凭据我的客户申请到一个我的服务应用 我可以使用公共和私人RSA密钥来实现这一点 但如果是这样 我不
  • 在 PowerShell 中从文件名中删除路径和扩展名

    我有一系列字符串 它们是文件的完整路径 我想只保存文件名 不保存文件扩展名和主路径 所以由此可知 c temp myfile txt to myfile 我实际上并没有遍历目录 在这种情况下类似于 PowerShell 的目录basenam

随机推荐

  • 支持泛型的 Java 动态代码生成

    有没有提供Java动态代码生成并且还支持泛型的工具 例如 Javassist 就是我需要的工具 但它不支持泛型 我编写了一个使用 Java 6 编译器 API 的小库 但据我所知它依赖于 JDK 有没有办法指定另一个编译器 或者只随我的应用
  • 软件评估 - 许可证 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 任何人都可以帮助我解决软件许可模块问题吗 我们创建了一个新应用程序 并希望发布我们工具的演示版本 30 天试用版 稍后我们需要完整版本 如
  • UITableViewCell 中的 AVPlayer.play() 会短暂阻塞 UI

    我正在尝试将内嵌视频添加到我的 UITableViewCells 如 Instagram Twitter Vine 等 我正在使用 AVPlayerController 和自定义单元通过本地视频文件测试 UI 请参阅下面的示例代码 我等待
  • 无法连接到atom.io 获取主题和包

    我相信我的工作代理阻止我向 Atom 添加主题和包 从首选项菜单中 我得到 获取特色包和主题失败 隐藏输出 tunneling socket could not be established cause 140499728967552 er
  • Scipy.Odr 多变量回归

    我想执行多维 ODRscipy odr 我读了 API 文档 它说多维是可能的 但我无法让它工作 我在互联网上找不到工作示例 而且 API 非常粗糙 没有给出如何继续的提示 这是我的 MWE import numpy as np impor
  • R 中的掩码方法

    这个问题 https stackoverflow com questions 30600958 using gather from tidyr changes my regression results 30638813特别是这个答案 ht
  • 谷歌地图矩形可编辑:如何锁定(固定)高度进行编辑

    我有一个谷歌地图 里面有一个可编辑 可移动和调整大小等的矩形 我正在寻找的是一种锁定矩形给定高度的方法 所以只有 宽度可以改变 您可以使用 JavaScript 中的bounds changed 事件来阻止矩形调整高度大小 这是一个工作的
  • COMPILE_FLAGS 和 COMPILE_OPTIONS 之间的区别

    有什么区别 COMPILE FLAGS 编译此目标源时使用的附加标志 and COMPILE OPTIONS 传递给编译器的选项列表 就最终的 VS2010 解决方案而言 这些命令产生相同的结果 target compile options
  • 如何链接独立的 C# 任务?

    假设我有两个独立的异步函数 我不控制 来创建任务对象 Task A Task B 以及其他一些非异步函数 void X 如何构建一个按顺序执行所有这些任务并允许附加进一步的延续 将在 X 之后执行 的单个任务链 如果我这样做 Task Se
  • 如何将Sinon 与Typescript 结合使用?

    如果我将 sinon 与 typescript 一起使用 那么如何将 sinon 模拟转换为我的对象的实例 例如 将返回一个SinonMock 但我的被测控制器可能需要将特定服务传递给其构造函数 var myServiceMock MySt
  • 如何正确配置 module.alias

    我想用resolve alias我的项目中使用 webpack 的功能反应入门套件 https github com kriasoft react starter kit 例如 相反 这个 import Component from com
  • 创建连续的动态矩阵

    数组具有作为连续内存块的良好特性 使用时new为数组分配内存 它返回一个指向连续的内存块 但是 如果我使用分配矩阵new 像这样 include
  • 如何显示修订历史记录

    Stack Overflow 如何以它们使用的类似 diff 的格式显示修订更改 我不关心 Stack Overflow 本身 这只是描述我的要求的一种便捷方式 我有文本字段更改的审核历史记录 我想以 Stack Overflow 显示修订
  • UIPickerView 编程示例?

    如何在不使用 Interface Builder 的情况下以编程方式在视图中设置 UIPickerView 还难以理解如何使用 UIPickerView 的委托部分 以编程方式添加 UIPickerView void pickerView
  • 如何说服 Visual Studio 使用 ADB 通过 TCP/IP 进行 Android 开发

    所以这可能有点边缘情况 但我在虚拟机上使用 Visual Studio 而且我手里拿着手机 我想进行设置 当我在 Visual Studio 中按 播放 时 它会编译我的 Cordova 应用程序 并将其推送到我旁边的手机上 以便我可以测试
  • 以独立于区域设置的方式访问 Windows 性能计数器

    我有一组混合服务器 一些运行英语 Windows 另一些运行意大利语 Windows 有没有一种方法可以在不使用与区域设置相关的字符串的情况下读取性能计数器的值 我读到Zabbix 文档 http www zabbix com docume
  • 获取 tkinter 文本小部件中的位置

    我正在尝试找到一种可靠的方法来获取 tkinter 文本小部件中的当前光标位置 到目前为止我所拥有的是 import tkinter as tk def check pos event print t index tk INSERT roo
  • 如何知道 Java SE 类或方法是否线程安全?

    例如 static private DateFormat df new SimpleDateFormat public static void format final Date date for int i 0 i lt 10 i new
  • Windows服务问题

    我有 3 个 Windows 服务问题 WS可以后台运行吗 是否可以每 2 分钟做一些工作 如果是的话 我可以寻求帮助吗 如何简单地安装WS 不与Installutil exe 如何从 Windows 服务运行 exe 文件 我试过这样 S
  • 如何在 PowerShell 中使用 S/MIME 对消息进行签名和加密

    我正在尝试创建一个 PowerShell 脚本 该脚本将 建立消息 使用我的私有 S MIME 证书对邮件进行签名 使用收件人的 S MIME 公共证书加密邮件 发送已签名并加密的电子邮件 我已经包含了下面的完整脚本 但更改了电子邮件地址