Tags:
The PowerShell Protect-CmsMessage and Unprotect-CmsMessage cmdlets provide an easy way to use RFC 5652 public key encryption of your data. This article gives example PowerShell code to use Protect-CmsMessage, as well as a discussion about limitations, issues, problems, error messages, etc..
You can download a script with all the following examples by going to BlueTeamPowerShell.com and getting the SEC505 zip file (look in the \Day1\Crypto folder inside the zip file for the Protect-CmsMessage_Examples.ps1 script). You'll find several other PowerShell scripts there related to cryptography too, such as for KeePass, the TrueRNG random number generator, and auditing the root CAs trusted by a Windows computer. All scripts are in the public domain.
The PowerShell scripts are part of the SANS Institute's six-day course on "Securing Windows and PowerShell Automation (SEC505)", which aims to teach Windows security and PowerShell at the same time.
Background
RFC 5652 describes how to encrypt and sign messages using public/private key pairs in a vendor-neutral way. These messages conform to the Cryptographic Message Syntax (CMS) as defined by the RFC. The Protect-CmsMessage and Unprotect-CmsMessage cmdlets are a PowerShell implementation of CMS. Data encrypted in PowerShell this way can be decrypted, for example, by OpenSSL on Linux.
These cmdlets make it very easy to strongly encrypt passwords, credit card numbers, firewall configuration scripts, and other secrets which can then be stored securely or sent over the Internet with Invoke-WebRequest or Send-MailMessage. When combined with PowerShell scripting for the KeePass password manager, many useful options become available for coders who need to manage large numbers secrets.
Requirements
The Protect-CmsMessage and Unprotect-CmsMessage cmdlets require PowerShell 5.0 or later.
Windows 10, Server 2016 and later come with PowerShell 5.0 or later by default, but earlier operating system owners will need to download the latest version of PowerShell from Microsoft.
The Protect-CmsMessage cmdlet requires a public key from a digital certificate, but not just any certificate will work. Here are the requirements for the public key certificate:
- The certificate must include the "Data Encipherment" or "Key Encipherment" Key Usage in the property details of the certificate.
- The certificate must include the "Document Encryption" Enhanced Key Usage (EKU), which is identified by OID number 1.3.6.1.4.1.311.80.1.
To confirm that your intended certificate meets these requirements, double-click the certificate file (.cer) to view its properties, go to the Details tab, and confirm that the "Enhanced Key Usage" property at least includes this line:
- Document Encryption (1.3.6.1.4.1.311.80.1)
And also in that certificate's properties, confirm that the "Key Usage" field includes one or both of these:
- Key Encipherment
- Data Encipherment
If your certificate is already imported into your local profile, then run MMC.EXE, add the Certificates snap-in (File menu) and double-click the desired certificate in your list of Personal certificates. You can also right-click that certificate > All Tasks > Export, in order to export the certificate to a file (.cer), but do not export the private key associated with this certificate.
If you are using a Windows PKI to obtain certificates, the template used must be configured correctly for CMS encryption. In the certificate template, you must ensure that:
- On the Request Handling tab, you have selected "Encryption" or "Signature and Encryption", and
- On the Extensions tab, you have selected Application Policies and then have added "Document Encryption" to the list of Application Policies.
(Note: If you are not familiar with Windows PKI management, search Microsoft's web site or attend the SANS six-day course SEC505, which includes a full day on Windows PKI. You can also create your own self-signed certificate, which is easier for getting started or testing, but is usually not recommended for production use.)
Officially, the data to be encrypted must be smaller than 2GB, which implies you can encrypt up to 2GB in a single CMS message, but see below for issues/errors.
Specifying the Certificate to Use
The certificate used by Protect-CmsMessage can be given to the cmdlet in various ways with the "-To" parameter:
- Path to an exported certificate file (.cer)
- Path to a directory containing an exported certificate file (.cer)
- Thumbprint hash value of the certificate in the user's Cert:\ drive
- The certificate's subject name, to be found in the user's Cert:\ drive
- A certificate object stored in a variable
The most intuitive way to do it is to export your certificate to a file (.cer) and provide the full explicit path.
If you provide the path to a folder, the Protect-CmsMessage cmdlet will search that folder for certificate files, select the first one it finds, and try that one. If this fails for any reason, like if the certificate does not meet the EKU requirements, then you'll get a terminating error and no other certificates from that folder will be attempted. There does not appear to be any way to specify the order or give preference to one certificate over another in the folder, such as key size or expiration date, other than with your own code, but, in this case, you end up giving the full path to the desired certificate file anyway.
Using a thumbprint precisely specifies exactly one certificate, which can be good, but it also means you must update that hash value in your code whenever the desired certificate is changed. If you search by subject name using a wildcard, you might get back an array of matching certificates, so take care to choose the correct one. For these reasons, it is often simplest to export the desired certificate to a file, use a standardized file name, and give the explicit path to this file.
For an example of using a certificate stored in a variable in memory, see below. This is convenient when you want to embed the desired certificate inside your script, hence, there is no external certificate file or path to worry about, i.e., the script is a one-file "package" so to speak. If such a script were digitally signed, it helps to ensure integrity and that only the intended public key certificate will be used by Protect-CmsMessage.
Example Code
Here is some example code to get started. This assumes you already have an exported certificate that meets the above requirements and that the associated private key with that certificate is in your local profile.
The output of each encryption operation will be Base64 text, similar to the following:
-----BEGIN CMS----- MIIB4AYJKoZIhvcNAQcDoIIBwTCCAb0CAQAxggF4MIIBdAIBADBcMEUxFTATBgoJkiaJk/IsZAEZ FgVsb2NhbDEXMBUGCgmSJomT8ixkARkWB4Rlc3RpbmcxEzARBgNVBAMTClRlc3RpbmctQ0ECE1sA AACI573u9cj1hfAAAAAAAIgwDQYJKoZIhvcNAQEHMAAEggEAeQ8el2gKzvP9p+g681LaBAICWB98 Tf8t7Mth7ml3fD2mwAaI4NH4m5NXDAJTpJn22axBRbqOYZI4XovIAYgX0fSH8gt0sl5aOwGMt61W v3VFLdTr9hTg4vCd6NVut1R5G54odbk8D9V92gH0Fys9s3tNX22TnREkrKeqZsfowdoxeId3Jkwn kg/ONt8ZOSCZKQIeD57IX8UTXmK+D8Q8GuO1cFLwYjZmnlYdXQZ4SDNqAi/XSZAkvVEUChJAD6Nm 1SxAjm0Fy89NBrqSfvX6vy/55v+J11hzYGVlm1be7u2CyjmdQ05r3tV2Q2iwpViDYaknP1P5muEJ YmPaAhVSODA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBKkzVjYTsYW0Aq2d4EgwAIgBDUCb3B IIvMCLR1lmmK2hAs -----END CMS-----
The above ciphertext can be captured to a variable, saved directly to file, posted with Invoke-WebRequest, e-mailed with Send-MailMessage, etc.
# To encrypt the contents of a variable using an exported certificate: $x = get-process #Some object data to protect Protect-CmsMessage -To .\ExportedCert.cer -Content $x -OutFile EncryptedVar.cms # To encrypt a TEXT file using an exported certificate, saving the output to a new file: Protect-CmsMessage -To .\ExportedCert.cer -Path .\SecretDocument.txt -OutFile EncryptedDoc.cms # To encrypt a variable or TEXT file using an exported certificate, capturing the output to a new variable: $CipherText1 = Protect-CmsMessage -To .\ExportedCert.cer -Content $x $ciphertext2 = Protect-CmsMessage -To .\ExportedCert.cer -Path .\SecretDocument.txt # To decrypt CMS ciphertext, assuming you have the private key: $plaintext = Unprotect-CmsMessage -Path .\EncryptedVar.cms $plaintext = Unprotect-CmsMessage -Content $CipherText1 $plaintext = Unprotect-CmsMessage -Path .\EncryptedFile.cms
Not A Property Bag
Importantly, when an object is encrypted, it is only the simple ToString() representation of that object which gets encrypted, not the whole "property bag" of the object; hence, it is not (usually) possible to recreate the original object in memory again like with Import-Csv or Import-CliXml.
If you want to reflate an array of objects in memory after decryption with Unprotect-CmsMessage, first convert the array to CSV or XML string data, encrypt with Protect-CmsMessage, decrypt with Unprotect-CmsMessage, then reflate the objects from the plaintext CSV or XML data. To call an object a "property bag" means that it lacks methods, but it also implies that the object can be serialized and then recreated again. In that sense, Protect-CmsMessage does not serialize objects or property bags, and Unprotect-CmsMessage does not reflate, recreate or deserialize the original object or property bag after decryption.
In general, do not expect the (Un)Protect-CmsMessage cmdlets to work reliably with anything other than textual data.
Encrypting Binary Files
What about encrypting and decrypting binary files or binary data then?
The following commands DO NOT WORK, they fail to restore the original file:
# This does NOT work with binary or EXE files: Protect-CmsMessage -To .\ExportedCert.cer -Path .\InputFile.exe -OutFile OutputFile.cms Unprotect-CmsMessage -Path .\OutputFile.cms | Set-Content -Path RestoredFile.exe # When the original and restored files are hashed, the hashes will NOT match: Get-FileHash -Path .\InputFile.exe,.\RestoredFile.exe
Nor can you make the above commands work by specifying "Set-Content -Encoding Byte": this raises an error because the output of Unprotect-CmsMessage is text, not an array of bytes.
But if you Base64-encode the binary data first, which converts the raw bytes to a textual representation, then that text can be encrypted with Protect-CmsMessage.
# A couple helper functions to go to/from Base64 and binary: function Convert-FromBinaryFileToBase64 { [CmdletBinding()] Param ( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] $Path, [Switch] $InsertLineBreaks ) if ($InsertLineBreaks){ $option = [System.Base64FormattingOptions]::InsertLineBreaks } else { $option = [System.Base64FormattingOptions]::None } [System.Convert]::ToBase64String( $(Get-Content -ReadCount 0 -Encoding Byte -Path $Path) , $option ) } function Convert-FromBase64ToBinaryFile { [CmdletBinding()] Param( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] $String , [Parameter(Mandatory = $True, Position = 1, ValueFromPipeline = $False)] $OutputFilePath ) [System.Convert]::FromBase64String( $String ) | Set-Content -Path $OutputFilePath -Encoding Byte } # Convert the binary file to Base64 strings, then encrypt: dir .\InputFile.exe | Convert-FromBinaryFileToBase64 | Protect-CmsMessage -To .\ExportedCert.cer -OutFile OutputFile.cms # Then the file can be decrypted and the Base64 converted back into a binary file again: Unprotect-CmsMessage -Path .\OutputFile.cms | Convert-FromBase64ToBinaryFile -OutputFilePath .\RestoredFile.exe # Now the hashes will match: Get-FileHash -Path .\InputFile.exe,.\RestoredFile.exe
Unfortunately, the performance of the above is horrible. A 20MB CMS file, for example, will require more than 10 minutes to decrypt on an Intel Core i7 4790 @ 3.60GHz. Maybe I'm making an obvious mistake in my code, but there are other issues too.
Limitations, Performance and Error Messages
The most important limitation is that Protect-CmsMessage should only be used to encrypt text or text files, nothing else.
When encrypting objects as text, if you'll need to recreate the original objects or property bags again later, convert the in-memory objects to XML or CSV first, then encrypt that XML/CSV text instead.
If you need to encrypt raw byte arrays or arbitrary binary data, encode that data in Base64, then encrypt the Base64 text.
What is the maximum amount of text that can be encrypted? If you attempt to encrypt more than 2GB of data, the error message is:
- Protect-CmsMessage : The file is too long. This operation is currently limited to supporting files less than 2 gigabytes in size.
So the official limit is 2GB, which is fine, nothing can handle infinitely-large files (even 7-Zip can't handle files larger than...ahem...16,000,000,000 GB), but if you attempt to encrypt even 1GB of data, you'll get a different error:
- Protect-CmsMessage : Exception of type 'System.OutOfMemoryException' was thrown.
The above error was produced on a machine with 32GB of memory, a 4GB paging file, a freshly relaunched PowerShell ISE, having run [GC]::Collect() on a fully patched Windows 10 Pro (Aug'2015). So what is the actual maximum file size limit then?
If you encrypt a 200MB text file, it works, but when attempting to decrypt that CMS output file, another error appears:
- Unprotect-CmsMessage : ASN1 value too large.
At this point, I stopped the size testing, the cmdlets are not reliable at anything near the official 2GB limit. At 1/100th the official maximum (20MB) there were no error messages and the hash testing was fine. Perhaps 20MB is the practical limit then? This is just a guess. The next step would be to start playing with the underlying System.Security.Cryptography.Pkcs.EnvelopedCms class to whether the limits come from the underlying class or the cmdlet wrappers.
Because of size and performance issues, if you need to quickly encrypt a large amount of data of arbitrary format, I suggest using Protect-CmsMessage to encrypt a 100-character random passphrase and then using that passphrase with 7-Zip to compress and encrypt the data (100 characters * 3 bits of entropy per char = the 7-Zip AES key with some extra entropy cushion). PowerShell 5.0 and later includes the Compress-Archive cmdlet, but this cannot encrypt archives and is not as fast or reliable as 7-Zip with large archives. There are nice 7-Zip modules in the PSGallery too. You could also do a script to create, mount and BitLocker-encrypt a VHD virtual machine image file, then copy the data into that VHD.
(If you wish to use a more pure PowerShell solution, check out Dave Wyatt's excellent ProtectedData module.)
Using Get-CmsMessage
The Get-CmsMessage cmdlet displays metadata about CMS-encrypted contents, but cannot decrypt those contents. You might use this cmdlet when receiving or organizing many CMS messages.
# Display metadata about a CMS message, but not decrypt it: Get-CmsMessage -Path .\little.cms "test data" | Protect-CmsMessage -To .\ExportedCert.cer | Get-CmsMessage # The output may scroll by for several pages, so this will display just # some of the metadata and in a more-useful form: # Which certificate was used to encrypt the data: Get-CmsMessage -Path .\little.cms | Select -ExpandProperty Recipients (Get-CmsMessage -Path .\little.cms).Recipients # Content type is PKCS #7 because of the historical roots of CMS (see RFC 5652): Get-CmsMessage -Path .\little.cms | Select -ExpandProperty ContentInfo | Select -ExpandProperty ContentType (Get-CmsMessage -Path .\little.cms).ContentInfo.ContentType.FriendlyName # Encryption type is AES 256: Get-CmsMessage -Path .\little.cms | Select -ExpandProperty ContentEncryptionAlgorithm | Select -ExpandProperty Oid (Get-CmsMessage -Path .\little.cms).ContentEncryptionAlgorithm.Oid.FriendlyName
Certificate Embedded In Script
Instead of reading the recipient's certificate from a file or from your own certificate store in your profile, the certificate can be encoded as hexadecimal text in a byte array and embedded right inside the script. This is handy when you want to use a one-file-only solution and avoid the hassles of managing both a script and separate certificate files.
The downside, of course, is that it becomes more difficult to change that certificate or to use other certificates at different times for different payloads.
This is also a technique to be aware of for the sake of malware forensics or investigating the post-exploitation use of PowerShell on a compromised machine.
So, how exactly do you embed a certificate in a script? How is this embedded certificate given to Protect-CmsMessage?
# First, get the public key certificate into a byte array from a file. [Byte[]] $CertBytes = Get-Content -Encoding Byte -Path ".\ExportedCert.cer" # Next, convert the certificate Byte[] array to hex: function Convert-ByteArrayToHexString { ################################################################ #.Synopsis # Returns a hex representation of a System.Byte[] array as # one or more strings. Hex format can be changed. #.Parameter ByteArray # System.Byte[] array of bytes to put into the file. If you # pipe this array in, you must pipe the [Ref] to the array. # Also accepts a single Byte object instead of Byte[]. #.Parameter Width # Number of hex characters per line of output. #.Parameter Delimiter # How each pair of hex characters (each byte of input) will be # delimited from the next pair in the output. The default # looks like "0x41,0xFF,0xB9" but you could specify "\x" if # you want the output like "\x41\xFF\xB9" instead. You do # not have to worry about an extra comma, semicolon, colon # or tab appearing before each line of output. The default # value is ",0x". #.Parameter Prepend # An optional string you can prepend to each line of hex # output, perhaps like '$x += ' to paste into another # script, hence the single quotes. #.Parameter AppendComma # Appends a comma to each line of output, except the last. #.Parameter AddQuotes # A switch which will enclose each line in double-quotes. #.Example # [Byte[]] $x = 0x41,0x42,0x43,0x44 # Convert-ByteArrayToHexString $x # # 0x41,0x42,0x43,0x44 #.Example # [Byte[]] $x = 0x41,0x42,0x43,0x44 # Convert-ByteArrayToHexString $x -width 2 -delimiter "\x" -addquotes # # "\x41\x42" # "\x43\x44" ################################################################ [CmdletBinding()] Param ( [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [System.Byte[]] $ByteArray, [Parameter()] [Int] $Width = 10, [Parameter()] [String] $Delimiter = ",0x", [Parameter()] [String] $Prepend = "", [Parameter()] [Switch] $AddQuotes, [Parameter()] [Switch] $AppendComma ) if ($Width -lt 1) { $Width = 1 } if ($ByteArray.Length -eq 0) { Return } $FirstDelimiter = $Delimiter -Replace "^[\,\:\t]","" $From = 0 $To = $Width - 1 Do { $String = [System.BitConverter]::ToString($ByteArray[$From..$To]) $String = $FirstDelimiter + ($String -replace "\-",$Delimiter) $From += $Width $To += $Width if ($AppendComma -and $From -lt $ByteArray.Length) { $String = $String + ',' } if ($AddQuotes) { $String = '"' + $String + '"' } if ($Prepend -ne "") { $String = $Prepend + $String } $String } While ($From -lt $ByteArray.Length) } # Copy the hex string to the clipboard: Convert-ByteArrayToHexString -ByteArray $CertBytes -AppendComma | Set-Clipboard # Now paste the hex strings into your script to make a Byte[] array. # Notice how each line ends with a comma indicating line continuation. # You'll need to add the first line yourself: [Byte[]] $CertBytes = 0x30,0x82,0x06,0xB4,0x30,0x82,0x04,0x9C,0xA0,0x03, 0x02,0x01,0x02,0x02,0x13,0x5B,0x00,0x00,0x00,0x88, 0xE7,0xBD,0xEE,0xF5,0xC8,0xF5,0x85,0xF0,0x00,0x00, 0x00,0x00,0x00,0x88,0x30,0x0D,0x06,0x09,0x2A,0x86, 0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, 0x45,0x31,0x15,0x30,0x13,0x06,0x0A,0x09,0x92,0x26, 0x89,0x93,0xF2,0x2C,0x64,0x01,0x19,0x16,0x05,0x6C, 0x6F,0x63,0x61,0x6C,0x31,0x17,0x30,0x15,0x06,0x0A, 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x19, 0x16,0x07,0x74,0x65,0x73,0x74,0x69,0x6E,0x67,0x31, 0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A, 0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0x2D,0x43,0x41, 0x30,0x1E,0x17,0x0D,0x31,0x35,0x30,0x38,0x32,0x30, 0x30,0x36,0x33,0x37,0x33,0x34,0x5A,0x17,0x0D,0x31, 0x37,0x30,0x38,0x32,0x30,0x30,0x36,0x34,0x37,0x33, 0x34,0x5A,0x30,0x4F,0x31,0x15,0x30,0x13,0x06,0x0A, 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x19, 0x16,0x05,0x6C,0x6F,0x63,0x61,0x6C,0x31,0x17,0x30, 0x15,0x06,0x0A,0x09,0x92,0x26,0x89,0x93,0xF2,0x2C, 0x64,0x01,0x19,0x16,0x07,0x74,0x65,0x73,0x74,0x69, 0x6E,0x67,0x31,0x0D,0x30,0x0B,0x06,0x03,0x55,0x04, 0x0B,0x13,0x04,0x48,0x6F,0x6D,0x65,0x31,0x0E,0x30, 0x0C,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x4A,0x61, 0x73,0x6F,0x6E,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, 0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01, 0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, 0x0A,0x02,0x82,0x01,0x01,0x00,0xAA,0x6C,0x65,0xDD, 0x4E,0x12,0x62,0x5E,0xBB,0xB3,0x3C,0x46,0x04,0x2A, 0xF7,0xFE,0x9F,0x10,0xB4,0x73,0x38,0x57,0x11,0x97, 0x07,0x56,0x52,0x75,0x43,0x14,0x65,0x2C,0x6F,0xA2, 0xDD,0x14,0xE5,0x31,0x65,0x5C,0x38,0x79,0x94,0x8E, 0x2D,0x1E,0x3B,0x13,0xF0,0x8D,0x8F,0x83,0xD1,0xA6, 0x89,0x87,0xE7,0x33,0x8F,0xD2,0xFA,0x9D,0x28,0x3F, 0x66,0x24,0xDB,0xB9,0xBD,0x23,0x88,0xAA,0xCC,0x9D, 0xE0,0x88,0xE6,0x37,0xD8,0x0B,0x04,0x26,0x39,0x8C, 0xBD,0xAA,0x30,0x22,0xBF,0xB4,0xB3,0xAB,0x43,0x5D, 0xC1,0xB1,0x12,0x64,0xD7,0xF6,0x57,0xB4,0x9B,0x34, 0x66,0x28,0x71,0x06,0x0A,0x71,0xC6,0x95,0xF0,0x8E, 0x9F,0x5B,0x08,0xFE,0x3D,0x0A,0x24,0x5A,0x36,0xAD, 0xF9,0x3D,0x37,0x76,0x8C,0xA6,0x8B,0xD1,0xCD,0xB9, 0x13,0x57,0x1F,0x3A,0xB3,0x0A,0x3B,0xE7,0x1E,0xF0, 0xD1,0xFD,0xB2,0x0D,0x54,0xDE,0x9A,0x45,0xD2,0x2F, 0x63,0x32,0xE4,0x0B,0xD7,0xBE,0x86,0xF0,0xF7,0xAD, 0x3B,0xE8,0x04,0x73,0x32,0xDF,0x78,0xE4,0xCC,0xE1, 0xD4,0x91,0x34,0x34,0xFA,0x44,0x30,0x25,0x7B,0x13, 0x1C,0xC6,0x29,0x56,0x57,0xA2,0x89,0xDB,0x1C,0x60, 0xCE,0xF3,0xE4,0x8B,0xD9,0x28,0xFA,0xE1,0xF7,0xC4, 0xCE,0xF2,0xA9,0x29,0xCF,0xCC,0xFD,0x84,0x83,0xE5, 0xBB,0x43,0xB2,0xE0,0xC0,0x10,0x92,0xB3,0x75,0xEE, 0xBD,0x06,0x48,0xEF,0x5E,0x44,0x91,0x85,0xEF,0x0F, 0xEB,0x4C,0x24,0xB2,0xC0,0x68,0xBD,0x47,0xBC,0xE7, 0x8F,0x23,0xBC,0x08,0x77,0x36,0x44,0x47,0xAD,0x0A, 0x3D,0x67,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02, 0x91,0x30,0x82,0x02,0x8D,0x30,0x3E,0x06,0x09,0x2B, 0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x07,0x04,0x31, 0x30,0x2F,0x06,0x27,0x2B,0x06,0x01,0x04,0x01,0x82, 0x37,0x15,0x08,0x87,0xDC,0xA1,0x40,0x86,0x93,0xE1, 0x24,0x85,0x99,0x9F,0x15,0x84,0xEB,0xF1,0x6B,0x84, 0x9C,0xD4,0x02,0x81,0x0E,0x85,0x90,0xA5,0x2C,0x83, 0x93,0xA7,0x6E,0x02,0x01,0x64,0x02,0x01,0x14,0x30, 0x1E,0x06,0x03,0x55,0x1D,0x25,0x04,0x17,0x30,0x15, 0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x50, 0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03, 0x02,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, 0xFF,0x04,0x04,0x03,0x02,0x05,0x20,0x30,0x28,0x06, 0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x0A, 0x04,0x1B,0x30,0x19,0x30,0x0B,0x06,0x09,0x2B,0x06, 0x01,0x04,0x01,0x82,0x37,0x50,0x01,0x30,0x0A,0x06, 0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30, 0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, 0x07,0xA8,0x43,0xB0,0x8A,0xB6,0x27,0x5E,0x28,0xC4, 0x5C,0x9C,0x83,0x83,0x64,0x1D,0x98,0xF3,0x8A,0xAB, 0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, 0x16,0x80,0x14,0x45,0x6F,0xDD,0xCC,0x30,0xF3,0xA5, 0xAD,0xB1,0xB8,0xD5,0x32,0x1F,0x1F,0xC2,0x1B,0x8C, 0xEB,0x0E,0xA4,0x30,0x81,0xC5,0x06,0x03,0x55,0x1D, 0x1F,0x04,0x81,0xBD,0x30,0x81,0xBA,0x30,0x81,0xB7, 0xA0,0x81,0xB4,0xA0,0x81,0xB1,0x86,0x81,0xAE,0x6C, 0x64,0x61,0x70,0x3A,0x2F,0x2F,0x2F,0x43,0x4E,0x3D, 0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0x2D,0x43,0x41, 0x2C,0x43,0x4E,0x3D,0x44,0x43,0x2C,0x43,0x4E,0x3D, 0x43,0x44,0x50,0x2C,0x43,0x4E,0x3D,0x50,0x75,0x62, 0x6C,0x69,0x63,0x25,0x32,0x30,0x4B,0x65,0x79,0x25, 0x32,0x30,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, 0x2C,0x43,0x4E,0x3D,0x53,0x65,0x72,0x76,0x69,0x63, 0x65,0x73,0x2C,0x43,0x4E,0x3D,0x43,0x6F,0x6E,0x66, 0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C, 0x44,0x43,0x3D,0x74,0x65,0x73,0x74,0x69,0x6E,0x67, 0x2C,0x44,0x43,0x3D,0x6C,0x6F,0x63,0x61,0x6C,0x3F, 0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74, 0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F, 0x6E,0x4C,0x69,0x73,0x74,0x3F,0x62,0x61,0x73,0x65, 0x3F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x43,0x6C,0x61, 0x73,0x73,0x3D,0x63,0x52,0x4C,0x44,0x69,0x73,0x74, 0x72,0x69,0x62,0x75,0x74,0x69,0x6F,0x6E,0x50,0x6F, 0x69,0x6E,0x74,0x30,0x81,0xE8,0x06,0x08,0x2B,0x06, 0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0xDB,0x30, 0x81,0xD8,0x30,0x81,0xAB,0x06,0x08,0x2B,0x06,0x01, 0x05,0x05,0x07,0x30,0x02,0x86,0x81,0x9E,0x6C,0x64, 0x61,0x70,0x3A,0x2F,0x2F,0x2F,0x43,0x4E,0x3D,0x54, 0x65,0x73,0x74,0x69,0x6E,0x67,0x2D,0x43,0x41,0x2C, 0x43,0x4E,0x3D,0x41,0x49,0x41,0x2C,0x43,0x4E,0x3D, 0x50,0x75,0x62,0x6C,0x69,0x63,0x25,0x32,0x30,0x4B, 0x65,0x79,0x25,0x32,0x30,0x53,0x65,0x72,0x76,0x69, 0x63,0x65,0x73,0x2C,0x43,0x4E,0x3D,0x53,0x65,0x72, 0x76,0x69,0x63,0x65,0x73,0x2C,0x43,0x4E,0x3D,0x43, 0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69, 0x6F,0x6E,0x2C,0x44,0x43,0x3D,0x74,0x65,0x73,0x74, 0x69,0x6E,0x67,0x2C,0x44,0x43,0x3D,0x6C,0x6F,0x63, 0x61,0x6C,0x3F,0x63,0x41,0x43,0x65,0x72,0x74,0x69, 0x66,0x69,0x63,0x61,0x74,0x65,0x3F,0x62,0x61,0x73, 0x65,0x3F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x43,0x6C, 0x61,0x73,0x73,0x3D,0x63,0x65,0x72,0x74,0x69,0x66, 0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x41,0x75,0x74, 0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x28,0x06,0x08, 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x1C, 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x64,0x63,0x2E, 0x74,0x65,0x73,0x74,0x69,0x6E,0x67,0x2E,0x6C,0x6F, 0x63,0x61,0x6C,0x2F,0x6F,0x63,0x73,0x70,0x30,0x0D, 0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, 0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x83,0xF9, 0x72,0x6A,0x54,0x51,0xC7,0x81,0x10,0x3E,0x82,0x38, 0x78,0x95,0x81,0xE0,0x8E,0x23,0xDF,0x89,0xB7,0x50, 0xD2,0x2E,0xC0,0xFF,0x7E,0x7A,0xDA,0x68,0xD2,0x5F, 0x8D,0x1A,0xA3,0x90,0x5B,0x1F,0x5A,0x3C,0x60,0xB4, 0x88,0x42,0xA9,0x6D,0xF0,0x35,0x5C,0xDD,0x8D,0x35, 0xE0,0x17,0x51,0x9E,0x52,0xD3,0xC3,0x58,0x5B,0x10, 0xD0,0x76,0x3E,0x9A,0x8A,0xA3,0xCE,0x1E,0xBF,0xCF, 0xA9,0x40,0x5D,0xC1,0x16,0x25,0x07,0x25,0x46,0xE7, 0x3D,0x0A,0x34,0x8F,0xD3,0x16,0x21,0x39,0x7D,0x7E, 0x54,0x64,0x52,0x45,0x54,0x0A,0x57,0xB0,0xCB,0xCD, 0x41,0x29,0x96,0xA6,0x5D,0x8C,0xD9,0x0F,0x45,0x3B, 0x40,0x06,0xB0,0x30,0x85,0x50,0x6C,0xE7,0xCE,0xDA, 0x0D,0xA2,0xA6,0x21,0x8D,0x1D,0x83,0xF0,0x3F,0xF8, 0xA7,0x2B,0x58,0x00,0xF7,0x99,0x21,0x24,0xEA,0x87, 0x5B,0xBB,0x6F,0xEB,0xB1,0x31,0x93,0x45,0xD6,0xFA, 0x0D,0x22,0xB3,0x8A,0x88,0xCC,0x4F,0x60,0x07,0x11, 0x16,0x14,0xDB,0x94,0x89,0x9D,0x74,0xE1,0x70,0xED, 0x45,0x18,0x2C,0x09,0xA3,0xB5,0x94,0x23,0xA6,0x66, 0x3E,0xD2,0xB0,0xA2,0xE3,0x23,0x32,0x90,0x96,0xAB, 0xB3,0xB5,0x22,0x27,0xB6,0x06,0xFF,0x6F,0x3D,0xA4, 0x46,0x67,0xA7,0xC9,0xD5,0x5C,0x43,0x88,0x66,0x37, 0xE8,0x4A,0xD3,0x9E,0x43,0x4F,0xA3,0x93,0x39,0x6F, 0x15,0x6E,0xCD,0x48,0x99,0xC1,0x54,0x7E,0xE3,0x12, 0xEC,0x89,0xCC,0x22,0xDE,0x3E,0x12,0x13,0xB5,0x32, 0x1A,0x3E,0xD2,0xA3,0x21,0x6A,0xC5,0xAD,0x81,0x8E, 0x2F,0x9E,0x61,0xBD,0x50,0xAE,0x23,0xE5,0xB7,0xF7, 0x24,0xD1,0x28,0x39,0x99,0xB0,0xCD,0x74,0x47,0xA1, 0xB5,0xD0,0x09,0x53,0xEA,0xD8,0xAB,0x23,0x37,0x7A, 0x3C,0xAC,0x0D,0x7C,0xD0,0x86,0x44,0xD0,0x2B,0x76, 0x04,0xC9,0x1C,0x29,0x08,0x9E,0x7E,0xCD,0x7E,0xEC, 0x0A,0x31,0x75,0x97,0x3B,0xD3,0x39,0x45,0xDA,0xCD, 0xDB,0xC3,0x6E,0x6E,0x51,0x3C,0xCE,0x02,0x00,0x16, 0xDE,0xFF,0xDD,0x45,0x34,0xD4,0x12,0xDF,0x9D,0x35, 0x6F,0xC2,0x06,0x53,0x18,0xF5,0x71,0x3D,0x50,0xF7, 0xE1,0xF3,0x08,0x4D,0xFC,0xC2,0xC4,0x53,0xD6,0xB6, 0xBE,0xD3,0xBC,0x8B,0xE3,0xF8,0xAC,0xE9,0xD0,0x54, 0xAD,0x5F,0x44,0x7C,0xE0,0x55,0xFD,0xAA,0x28,0xD1, 0x74,0xDB,0xAB,0x41,0xB5,0x7B,0x0C,0x04,0x0A,0x9F, 0xAA,0xBE,0x34,0xF0,0x27,0x41,0xA6,0xF7,0xAE,0xF9, 0x24,0x3F,0x27,0x87,0x64,0xBD,0x36,0x02,0xF7,0x69, 0x08,0x84,0x4B,0x30,0x95,0x4A,0xCF,0x17,0xE5,0x96, 0xB3,0x20,0x4B,0x60,0x3A,0xC2,0x22,0x6D,0xFF,0x35, 0x04,0x60,0x3A,0x51,0xF0,0xDB,0x0B,0x51,0x7B,0x44, 0x4C,0x55,0x40,0xE0,0x17,0x88,0x3D,0x5D,0xD8,0x6E, 0x2B,0x87,0xCB,0xE3,0xE9,0x4D,0x2B,0x8B,0x59,0x85, 0x38,0x04,0x39,0xCF,0x44,0x6B,0x73,0x85,0x21,0x01, 0x25,0x51,0xAB,0x69,0xAA,0x33,0x03,0x13,0x50,0x2C, 0xEC,0x69,0xE4,0xCC,0x51,0x3C,0xDF,0x44,0xAF,0xE5, 0x5A,0xEC,0x57,0x1A,0xFB,0x5F,0x4F,0x7E,0x0C,0xFD, 0xC4,0xA0,0xC3,0x9D,0xD0,0x60,0x83,0x79,0x8B,0x65, 0xAF,0x2A,0xD3,0x00,0x46,0x49,0x86,0x8E,0x55,0xD3 # Create an X.509 certificate object from the byte array: $Cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (,$CertBytes) # Now the in-memory certificate object can be given to Protect-CmsMessage: $body = Protect-CmsMessage -To $Cert -Content "your message data"
Have fun!
Version History
23.Aug.2015: First posted
11.Jun.2016: Added 7-Zip links
13.Aug.2018: Fixed typo in Convert-FromBase64ToBinaryFile function.
17.May.2021: Fixed download link.