Encrypting and Decrypting Strings with a Key in PowerShell

Note:  After writing up this post,  I found a great script by Oisin up on Poshcode that does all of this using System.Security.Cryptography.RijndaelManaged in a much more elegant way, but I had fun hammering through some of this stuff so I thought I would share. I was recently working on a script that required encryption for some of the data. This has been dealt with quite a bit in the PowerShell Community. There are some great posts here (Lee Holmes Precision Computing) and here (/\/\o\/\/'s old blog). I had the unique constraint that the user who encrypts the data may not necessarily be the same user who decrypts it. The way I chose to solve this was with a Shared key, that both users would know. Here's where it gets a little tricky. All the cmdlets for managing Secure Strings seem to encrypt using some sort of hash from the given logged on user. This obviously would not work for use with a shared key. It turns out that there is a -key parameter on the ConvertTo-SecureString. There is also a -asPlainText parameter. But you can't use them both at the same time. They are in different parameter sets. This poses the question, How can you encrypt a plainText string with a key in PowerShell? Well here is what I came up with. First of all, we need to generate a key. Wouldn't it be nice if you could just use an alphanumeric string? But that wouldn't have been nearly as much fun. It turns out the key needs to be a 16,24, or 32 byte array. That made me come up with this handy little function:
function Set-Key {
param([string]$string)
$length = $string.length
$pad = 32-$length
if (($length -lt 16) -or ($length -gt 32)) {Throw "String must be between 16 and 32 characters"}
$encoding = New-Object System.Text.ASCIIEncoding
$bytes = $encoding.GetBytes($string + "0" * $pad)
return $bytes
}
It takes a string, forces the length, and then returns an appropriate byte array that we can use generate a key to encrypt stuff with. So the next hurdle is to actually encrypt a string of plain text with they key we generated. Even though you cannot encrypt a whole string in a secureString, there is a method on System.SecureString called AppendChar. So, if we break our string out in chars, we can build our SecureString.  
function Set-EncryptedData {
param($key,[string]$plainText)
$securestring = new-object System.Security.SecureString
$chars = $plainText.toCharArray()
foreach ($char in $chars) {$secureString.AppendChar($char)}
$encryptedData = ConvertFrom-SecureString -SecureString $secureString -Key $key
return $encryptedData
}
Finally, to decrypt everything, we can use a technique that /\/\o\/\/\ came up with a long time ago using [Runtime.InteropServices.Marshal]
function Get-EncryptedData {
param($key,$data)
$data | ConvertTo-SecureString -key $key |
ForEach-Object {[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($_))}
}
Here is how you could use these functions together to encrypt and decrypt strings to your heart's content: image  
187 >  $plainText = "Some Super Secret Password"
188 >  $key = Set-Key "AGoodKeyThatNoOneElseWillKnow"
189 >  $encryptedTextThatIcouldSaveToFile = Set-EncryptedData -key $key -plainText $plaintext
190 >  $encryptedTextThatIcouldSaveToFile
507964ed3a197b26969adead0212743c378a478c64007c477efbb21be5748670a7543cb21135ec324e37f80f66d17c76c4a75f6783de126658bce09ef19d50da
191 >  $DecryptedText = Get-EncryptedData -data $encryptedTextThatIcouldSaveToFile -key $key
192 >  $DecryptedText
Some Super Secret Password
Comments are closed