0

I need to store some credentials for an SMTP server in my script, but naturally I don't want to password to be stored in plaintext.

So far I've been encrypting the password like this:

"password" | ConvertTo-SecureString -AsPlainText -Force |
    ConvertFrom-SecureString

and using it in a script like this:

$password = "(the long string generated from above command)"
$username = "Test@testdomain.com"

$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,($password | ConvertTo-SecureString)

However, when generating the $cred object I get the following error:

ConvertTo-SecureString : Key not valid for use in specified state.
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
PnP
  • 3,133
  • 17
  • 62
  • 95
  • This could be helpful: http://stackoverflow.com/questions/7109958/saving-credentials-for-reuse-by-powershell-and-error-convertto-securestring-ke – Micky Balladelli Jan 31 '16 at 13:14
  • How/where do you want to use the script? You can't simply take the encrypted string and magically decrypt it anywhere without having to provide a key. The reason why decryption seemingly works without that for the user who created the encrypted string is because it's bound to the user password via the [Data Protection API](https://msdn.microsoft.com/en-us/library/ms995355.aspx) and Windows handles it transparently for the current user. – Ansgar Wiechers Jan 31 '16 at 14:00

3 Answers3

1

Remove the ConvertFrom-SecureString and Reload it like this:

$Password = "password" | ConvertTo-SecureString -AsPlainText -Force 
$username = "Test@testdomain.com"
$cred = New-Object System.Management.Automation.PsCredential($username, $Password)
Avshalom
  • 8,657
  • 1
  • 25
  • 43
  • I don't want to store the file in a text file - I would like it to be stored only in the script itself. – PnP Jan 31 '16 at 13:08
  • 3
    @PnP be aware that by default `ConvertTo-SecureString` will store its private key in key store of the user you use to create the key, and only that user will be able to decrypt the key in future. To make this work under different contexts you would need to create your own key (which you then need to store) – Michael B Jan 31 '16 at 13:36
  • 2
    Note, however, that if you're storing the key you could just as well store the password, because either way your security relies on the access permissions of the key/password location. – Ansgar Wiechers Jan 31 '16 at 14:02
  • 1
    @AnsgarWiechers You're completely correct, and that does become the next problem to solve. I have found certificate based encryption to be the solution to that set of problems. Since a certificate can be installed and stored securely. – Michael B Jan 31 '16 at 16:04
0

Maybe Protect-String with Unprotect-String in Carbon module is what you are looking for. I use it all the time and works beautifully.

Carbon is a PowerShell module for automating the configuration of computers running Windows 7, 8, 2008, and 2012.

atorres
  • 11
  • 4
  • While these links may provide relevant information, you cannot guarantee their availability. Please add the relevant information from those links to your answer. – Aleks G Feb 01 '16 at 13:08
-4

PLEASE READ the following carefully and think through the points before you decide this does not help the OP with his problem.

Encrypting a password using PS or .NET mechanisms is a case of "security through obscurity" unless one has a robust method to store the key. (The usual "robust methods" are "what I know", "what I am" (biometrics), and "what I have".) But obscurity is the level of security that the OP seems to be asking for ("naturally I don't want to password to be stored in plaintext"). And there's nothing wrong with that. But unlike cases where some security-through-obscurity is obtained because code is compiled, that's not the case w PS.

However, the security depends on who an "attacker" is considered to be. If you are dealing with a password that the current user generates, then the current user isn't an attacker. However it you are dealing with a password set by some other entity, but you need the user to use it, but not see it, then the current user is a potential attacker. (An example of this case: a script to join a workstation to a domain would need a user with right set of domain permissions. You might want the user to be able to join the domain as part of imaging/re-imaging his desktop, but you don't want his domain user account to have rights to join the domain, so your script uses a different set of credentials you don't want the user to know). I'm guessing the OP is asking about a case where the password is not assigned by the user. The rest of this answer addresses this case.

Using PS/.NET methods to encrypt/obtain password, is "security through obscurity" because an attacker only needs to put a breakpoint just before where password is used. With a variable name like $password it'll be easy to find a location to set the breakpoint. Obscuring the variable name (eg call the password variable $exectionContext which is a misspelling of a PS auto-variable) won't do much if 1) the script is short and/or 2) it's obvious what command requires the password.

So, instead of encrypting the password in what amounts to a fairly transparent and easy to reverse scheme, you can get what is arguably better security by just being tricky in setting $password (or whatever you call the var) to it's ultimate value. For example if the password is "join-thE_domain" you could do something like:

...other script code...
$windowTitle="Install/deinstaller joint script"
...other script code...
$paramName = "-th"
...other script code...
$status = "End main"
...other script code...
$subTitle = $windowTitle.substring(20,4)
...other script code...
$count = 32
...other script code...
# Use a regex in the following to make it more obscure
$fixedStatus = $status -replace "n","_" -replace "o",[string][char]$count
...other script code...
# If cmdlet/cmd doesn't support password as a positional parameter then 
# write a function that calls cmdlet/cmd and takes password as positional parm
cmdlet-that-needs-password "arg value 1" ("$subTitle$paramName"+$fixedStatus) "arg value 3"
...other script code... 
# extra code at the bottom is important to keep someone from 
# just scrolling to bottom of script to see password being used
# This extra code could be just dummy code that doesn't really do anything
# Extra code can be placed throughout the script to make it more obscure
...other script code... 
Χpẘ
  • 3,403
  • 1
  • 13
  • 22
  • Powershell makes using strong encryption a reasonably trivial matter. There is no need to make scripts obscure when you can simply protect the secrets with encryption. By default encryption is tied to the user account, so to insert a breakpoint an attacker needs access to that account to access the decrypted secret. If an attacker can do that then you've already been breached. Adding obscurity from that point just makes script maintenance considerably more difficult – Michael B Jan 31 '16 at 15:59
  • @MichaelB Strong encryption doesn't help if it is easily reversible (because the key isn't secured). Which would be the case here. – Χpẘ Jan 31 '16 at 17:05
  • 1
    Inventing your own obfuscation algorithm doesn't help either. – Ansgar Wiechers Jan 31 '16 at 17:42
  • @AnsgarWiechers Actually, it does, given what the OP said. He said he doesn't want the password stored in plain text. Given my explanation of how easy it would be to reverse engineer a statement or two that retrieves a password from an encrypted store, having a series of a dozen or more statements scattered throughout the script is much more opaque. Note that this kind of practice - deriving a secret, where the secret must be hard coded in the executable - by spreading out the construction of the secret over a wide area of the program is fairly standard practice. – Χpẘ Jan 31 '16 at 17:47
  • 1
    *\*yawn\** Revenge downvotes ar *so* lame. And trust me, they're hurting you a lot more than me. Have a nice day. – Ansgar Wiechers Jan 31 '16 at 18:09
  • @AnsgarWiechers Not fully reading and understanding someone's answers is lazy.Maybe that explains the yawn. – Χpẘ Jan 31 '16 at 18:31
  • 1
    How is it 'easy to retrieve a password from an encrypted store?' Without having the password to that account(the OP doesn't say it is to be protected from logged in users) and no matter how you obfuscate it, you can't escape the fact that at some point in the code you will have the parameter that says `-credential $No-Really-This-Isnt-A-Credential-Cause-Like-I-Hid-It-Really-Well` - Anyone who is capable of understanding how to unwrap encryption will know how to backtrack through a variable. Obfuscation like this adds nothing to security and a lot to administration and maintenance. – Michael B Jan 31 '16 at 20:34
  • @MichaelB OP is almost surely not trying to defeat a user who knows PS. There's no point in not storing the password in clear text if he was. I interpret that he's trying to prevent a casual user from seeing the password. I also am interpreting that the password he's protecting is not a password the user chose, but one that someone else (IT for example) chose. My post makes that distinction. I think if you'll *carefully* reread the answer you'll understand the problem (which occurs anytime you have encryption keys) and the point of my solution. – Χpẘ Jan 31 '16 at 20:34
  • I perfectly understand your point, 'lets hide the password so it can't be read' working on the presumption that you're dealing with a logged in user, how is that any better than actually encrypting a password and having clean code to work through. How does your solution solve the problem you state that you solve. Considering `Send-MailMessage` uses the `-credential` parameter for credentials. (as do most/all Powershell commands that need credentials) a user could simply put a breakpoint at the place it is used. Since it is plainly obvious and easy to reverse. – Michael B Jan 31 '16 at 20:51
  • I commented on that in the post too. There I said embed the cmdlet/cmd within a function. `Send-MailMessage` doesn't have a positional parameter to credentials, so the obfuscation (again target at a non-programming user) is to put `Send-MailMessage` into a function. That function's name could be obfuscated and the invocation of `Send-MailMessage` could be obfuscated as well (via IEX, &,[powershell]::create and other means). – Χpẘ Jan 31 '16 at 21:28
  • So we're hoping that the user is too stupid to know how to debug and check for a PSCredential object, yet suggesting (s)he is smart enough to debug and check for a decrypted string. Well good luck with that, I think I'll stick with good old fashioned encryption and security best practices, rather than hoping my users are stupid. – Michael B Feb 01 '16 at 00:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102186/discussion-between-user2460798-and-michael-b). – Χpẘ Feb 01 '16 at 01:28
  • @MichaelB There's nothing best practice about using easy reversible encryption. If I was working with a dev on a threat model for his design that would be one of the first things that would jump out and I would require to be changed. Best practice is to understand the security requirements, then the threat model and design to that. – Χpẘ Feb 01 '16 at 01:39