SecureStrings and Plain Text in PowerShell
A question came up today on the newsgroup asking why the following didn’t work:
PS >$secureString = ConvertTo-SecureString "Hello"
ConvertTo-SecureString : Cannot process argument because the value of argume
nt "input" is invalid. Change the value of the "input" argument and run the
operation again.
At line:1 char:39
+ $secureString = ConvertTo-SecureString <<<< "Hello"
PS >
For some background – a SecureString is a type of string that PowerShell (and .Net) keeps encrypted in memory. Even if an attacker can explore the memory on your computer (like the contents of a swap file, for example,) they cannot gain access to the secret protected by the SecureString.
Although you can pass around SecureStrings with impunity, applications must be extremely careful at the boundaries – when creating SecureStrings and retrieving the encrypted data from them. This means doing things like reading your password input character by character, then removing each character from memory as soon as possible. If the data is ever stored as a regular string, it stays in memory until the process exits.
By typing a regular string onto the command line (like in the example,) the string can no longer be made secure. That specific string stays in memory until PowerShell exits. This is why ConvertTo-SecureString only accepts the encrypted output of ConvertFrom-SecureString. Only in that way can we retain the security guarantee of SecureStrings.
That said, most people aren’t that concerned about an attacker spying on their machine’s memory, or digging through their Windows pagefile. In many situations, the benefit of being able to automate these situations vastly outweights the potential security risk.
For the upcoming release candidate, we’ve added some new functionality to allow this:
$secureString = ConvertTo-SecureString "Hello" -AsPlainText -Force
(The force flag lets you bypass the warning I just gave you :) )
Until then, you can create SecureStrings from plain text this way:
$text = "Hello World"
$secureString = new-object Security.SecureString
$text.ToCharArray() | % { $secureString.AppendChar($_) }
[Edit: Ouch… my first dupe!]