In continuing with my previous post, Secure Password with PowerShell: Encrypting Credentials Part 1, I'd like to talk about sharing credentials between different machines/users/etc.
To recap my last blog, part 1 of Encrypting Credentials, when you use ConvertTo-SecureString and ConvertFrom-SecureString without a Key or SecureKey, Powershell will use Windows Data Protection API (DPAPI) to encrypt/decrypt your strings. This means that it will only work for the same user on the same computer.
When you use a Key/SecureKey, the Advanced Encryption Standard (AES - wiki link) encryption algorithm is used. You are able to use the stored credential from any machine with any user so long as you know the AES Key that was used.
Here's a small snippet from my last blog post for easy reference for the two cmdlets:
The string to convert to a SecureString
Encryption key as a SecureString.
Encryption key as a byte array.
First, let’s show an example of what you will see if you try to create a credential from one machine (Machine 1) and then access it from another machine (Machine 2) without providing a key.
This will create the file Password.txt with an encrypted standard string representing the password. It will use DPAPI.
This will successfully get the encrypted standard string using Get-Content, and convert it to a SecureString.
This will fail with an error indicating that the key is invalid. Example below:
Now, let's show a simple example of creating an encrypted standard string with the use of a key. AES encryption only supports 128-bit (16 bytes), 192-bit (24 bytes) or 256-bit key (32 bytes) lengths, so we'll need to create or generate an appropriate key. For simplicity, let's create a simple byte array of ascending numbers. We'll use a 128-bit key, so we'll need a 16-byte array.
This will create the file (with Out-File) Password.txt with an encrypted standard string representing the password. It will use AES.
This will successfully get the encrypted standard string and convert it to a SecureString. It will use the AES key that we provided earlier.
This will successfully get the encrypted standard string and convert it to a SecureString by using the AES key.
Now that you know how to use an AES key to make SecureStrings created by different user accounts and workstations, you have to protect that key as best as you can since anybody who has that AES key can now decrypt the data protected.
In my previous example, I used a very simple 16-byte array that is stored in the body of the script itself. This is not a good practice and is essentially the same as if you were to write the password in clear text. Alternatively, you could create/generate a key beforehand in a separate script.
As an example, I have built a small script to generate a random 16-byte array. I have used the System.Security.Cryptography.RNGCryptoServiceProvider class to fill a byte array with randomly-generated data.
Creating AES key with random data and export to file
Creating SecureString object
Creating PSCredential object
That’s it! You will be able to use the key file to decrypt the password file from any machine with any user.
Be sure to protect that AES key as if it were your password. Anybody who can read the AES key can decrypt anything that was encrypted with it.
At the very least, you should implement strict NTFS access controls for both your password and key files. This should keep out most prying eyes. Additionally, you may consider storing the data in a database with strict access controls or even implementing public-key (asymmetric) cryptography for additional control.
In any case, you should be good to use AES keys with your SecureStrings now.
Did you know that PDQ Deploy has a PowerShell step you can use to deploy your scripts?
Kris was an employee at PDQ.