I get an error using a PowerShell script for encrypting/decrypting a file

I used the “#2” script found here: https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Encryption-45709b87

I get a problem when I run the commands line-by-line interactively. Here is the first line that gives me a problem:

$encryptedSecureKey = Get-Content .2-SecureStrings-AES.Key.txt

To get around the problem, I found that these two flags could be appended to the line above:
-AsPlainText -Force

But then I get a problem at this line:

$newSecureString = ConvertTo-SecureString -String $encryptedSecureString -Key $key

This is the error: “ConverTo-SecureString: The key is invalid.”

To diagnose this, I ran this:

echo $securekey.length

The result was 524. I therefore recreated the keys, but with one change. This line I changed the 32 to a smaller number.

$key = New-Object byte

When I change it to a 2, instead of a 32, the length ($securekey.length) got smaller. But it was still 460 (far above the max of 256). How do I get around this invalid key issue? Was this script not tested? Or am I doing something wrong? I am using Windows Server 2012.

The script is fine, so far as I know. I wrote it, and tested it. Just ran everything again to make sure it was okay.

$secureKey.Length should be 16. It’s the original 32-byte AES key, interpreted as a Unicode string (2 bytes per character, so a 16 “character” string). $encryptedSecureKey.Length will be much longer (524), because that’s the result of DPAPI encrypting your key.

You can’t add -AsPlainText -Force to Get-Content; those are parameters for ConvertTo-SecureString, and they’re not appropriate here. You don’t want the text in ‘2-SecureStrings-AES.Key.txt’ to be literally treated as a key, you want it to be decrypted by DPAPI back into its original 16-character string.

All that said, you’d probably have a much nicer time just using the ProtectedData module (or the CmsMessage commands, if you’re running a recent enough version of PowerShell.) Both options require you to create a certificate (which can be self-signed, no big deal), but then are much more user-friendly than having to mess around with all of the keys and code directly. https://gallery.technet.microsoft.com/Share-encrypted-data-2f91fd3f

This is what I generally use for encrypting credentials

$KeyFile = “C:\Temp\AES.key”
$Key = New-Object Byte 32 # You can use 16, 24, or 32 for AES
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | out-file $KeyFile
$PasswordFile = “C:\Temp\Password.txt”
$Key = Get-Content $KeyFile
$Password = “password” | ConvertTo-SecureString -AsPlainText -Force
$Password | ConvertFrom-SecureString -key $Key | Out-File $PasswordFile

and this is the snippet for decrypting the credentials

$User = “MyUserName”
$PasswordFile = “\Machine1\SharedPath\Password.txt”
$KeyFile = “\Machine1\SharedPath\AES.key”
$key = Get-Content $KeyFile
$MyCredential = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList $User, (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)

Hope you’ve put some strong security on that AES.key file. It’s plain text, just as sensitive as the password itself.

Yeah I store them on a network share with some pretty anal ACL’s only allowing the service accounts running my scripts access to the keys with auditing enabled on the folder. I don’t store them with my scripts as or on a share that is publically available.