Powershell - Password encryption/decryption with key - powershell

I am trying to encrypt and decrypt the password using the powershell. However not able to successfully decrypt
My code:
#Encryption
$KeyStoragePath="C:\Temp\Password"
$KeyFileName="AESKey.AES.Key"
$CreateKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($CreateKey)
$CreateKey | out-file ".\$KeyFileName"
$GetKey = Get-Content "$KeyStoragePath\$KeyFileName"
$CredentialsStoragePath = "C:\Temp\Password\"
$CredentialsFileName = "sec-string"
$PasswordSecureString = Read-Host -AsSecureString
$PasswordSecureString | ConvertFrom-SecureString -key $GetKey | Out-File -FilePath "$CredentialsStoragePath\$CredentialsFileName"
This successfully creates a secure file with secure string in it. However, cannot decrypt it with the key.
#Decrypt
$MyPasswordFile = "C:\Temp\Password\sec-string"
$MyPassword = Get-Content $PasswordFile | ConvertTo-SecureString -Key $CreateKey
Error
$MyPassword = Get-Content $PasswordFile | ConvertTo-SecureString -Key $CreateKey
ConvertTo-SecureString : Padding is invalid and cannot be removed.
At line:1 char:43
+ $MyPassword = Get-Content $PasswordFile | ConvertTo-SecureString -Key $CreateKey
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ConvertTo-SecureString], CryptographicException
+ FullyQualifiedErrorId : ImportSecureString_InvalidArgument_CryptographicError,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand

Use the right things in the right places. You should be decrypting the password with the key
#Encryption
$KeyStoragePath="C:\Temp\Password"
$KeyFileName="AESKey.AES.Key"
$CreateKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($CreateKey)
$CreateKey | out-file "$KeyStoragePath\$KeyFileName"
$GetKey = Get-Content "$KeyStoragePath\$KeyFileName"
$CredentialsStoragePath = "C:\Temp\Password\"
$CredentialsFileName = "sec-string"
$PasswordSecureString = Read-Host -AsSecureString
$PasswordSecureString | ConvertFrom-SecureString -key $GetKey | Out-File -FilePath "$CredentialsStoragePath\$CredentialsFileName"
#Decrypt
$MyPasswordFile = "C:\Temp\Password\sec-string"
$MyPassword = Get-Content $MyPasswordFile | ConvertTo-SecureString -Key $GetKey
# Additional code below will change to plain text but this is bad practice. You should not need the plaintext password. You can create a credential from the secure string
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MyPassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

Related

Passing secure text between two servers with powershell

I'm working on a script that export certificate from Server A to PFX, copy it to Server B and import the PFX to the server.
I'm using the following code to encrypt the password from plain text to secure string:
$pfxPass = "PassW0rd"
$File = "D:\backup_conf\Password.txt"
[Byte[]] $key = (1..16)
$pfxSecure = $pfxPass | ConvertTo-SecureString -AsPlainText -Force
$pfxSecure | ConvertFrom-SecureString -key $key | Out-File $File
dir Cert:\LocalMachine\my | Where-Object { $_.NotAfter -clike "*2019*"} | % { certutil.exe -f -exportPFX -p $pfxSecure $_.Thumbprint D:\backup_conf\certificates\$($_.Thumbprint).pfx }
PFX created and I can see that Password.txt contains the hash string.
The PFX and the Password.txt were copied over to new server and I've used the following code for import:
$file = "D:\backup_conf\Password.txt"
[Byte[]] $key = (1..16)
$pfxSecure = Get-Content $File | ConvertTo-SecureString -Key $key
$certs = (Get-ChildItem -recurse -Path "D:\backup_conf\certificates" -Include *.pfx)|%{Import-PfxCertificate $_.FullName -Exportable -Password $pfxSecure -CertStoreLocation Cert:\LocalMachine\My }
This one fails with the error:
Import-PfxCertificate : The PFX file you are trying to import requires either a different password or membership in an Active
Directory principal to which it is protected.
Any idea why it's not working?
As you're using SecureString object here: certutil.exe -f -exportPFX -p $pfxSecure it's not properly recognized by certutil.exe. Password will be literally
System.Security.SecureString
For cmd applications SecureString is not something it can process so you'll have to convert it to plain text and then pass it to certutil.exe.
Example how you can convert SecureString to plain text (source):
$SecurePassword = ConvertTo-SecureString $pfxPass
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

encrypt username in PowerShell

Need to encrypt username and password in PowerShell I've encrypted password using the below code.
$credential = Get-Credential
$credential.Password | ConvertFrom-SecureString |
Set-Content E:\powershell\encrypted_password1.txt
But when I tried to encrypt username with the same code
$credential.username | ConvertFrom-SecureString |
Set-Content E:\powershell\encrypted_user1.txt
Encountered with below error:
ConvertFrom-SecureString : The input object cannot be bound to any parameters
for the command either because the command does not take pipeline input or the
input and its properties do not match any of the parameters that take pipeline
input.
Is there any way to encrypt username?
Exporting:
$credential = Get-Credential
$credential.Password | ConvertFrom-SecureString | Set-Content E:\powershell\encrypted_password1.txt
$credential.Username | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Set-Content E:\powershell\encrypted_user1.txt
Importing:
$Username = Get-Content E:\powershell\encrypted_user1.txt | ConvertTo-SecureString
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Username)
$Username = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$Password = Get-Content E:\powershell\encrypted_password1.txt | ConvertTo-SecureString
$Credential = New-Object -TypeName PSCredential -ArgumentList $Username, $Password

ConvertTo-SecureString run without key on different user account, is there a way (with proper credentials) to get this working from a different user?

I have a VM that I have full access to with access to all accounts. My question below is all run on the same machine, just under different user accounts.
If I logon with domain\user1 and run the following PowerShell to generate a string of a SecureString:
$SecurePassword = "ThisIsATest" | ConvertTo-SecureString -AsPlainText -Force
$RawSecureString = $SecurePassword | ConvertFrom-SecureString
Write-Host $RawSecureString
So the output is below:
$RawSecureString = "01000000d08c9ddf0115d1118c7a00c04fc297eb0100000014c54a4678625849adf32615ece5d33f000000000200000000001066000000010000200000007ece54f23781b598d0341c2380e678bc6286222186717e612e0f095b3edc4137000000000e80000000020000200000006b68df76dbc98fcd35943be7818c80ed502ec49d0ae06deeec183367ea19e10d200000002087d6178d6a67165d41ed172e11eae6bf7d648a59d25c01dd573baaad985bb040000000adc87d779c7de9d1565bcb834e50214e982c133c3558111138a2e1964b599d1bcb7b4583ff18d314f7bc6a0549bf03342a49ba2456cc13df60585ca36125ae37"
With domain\user1 I run the following:
$SecureString = $RawSecureString | ConvertTo-SecureString
[System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($SecureString))
and the output is ThisIsATest, which is good.
If I logon as domain\user2 and run the following:
$RawSecureString = "01000000d08c9ddf0115d1118c7a00c04fc297eb0100000014c54a4678625849adf32615ece5d33f000000000200000000001066000000010000200000007ece54f23781b598d0341c2380e678bc6286222186717e612e0f095b3edc4137000000000e80000000020000200000006b68df76dbc98fcd35943be7818c80ed502ec49d0ae06deeec183367ea19e10d200000002087d6178d6a67165d41ed172e11eae6bf7d648a59d25c01dd573baaad985bb040000000adc87d779c7de9d1565bcb834e50214e982c133c3558111138a2e1964b599d1bcb7b4583ff18d314f7bc6a0549bf03342a49ba2456cc13df60585ca36125ae37"
$SecureString = $RawSecureString | ConvertTo-SecureString
[System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($SecureString))
I get Key not valid for use in specified state., because it's a different user.
Since there is no key provided during encryption by user1, my question is, if I have access to both logon accounts, is there a way from user2 to decrypt this secure string?
The reason is I have many VM's where keys were stored in the registry as the local administer account and most of what I'm doing is from a remote domain account.
Yes, but you will have to recreate the SecureStrings.
The strings encrypted by ConvertTo-SecureString can only be de-crypted by the same computer and user account that encrypted them by default.
You can use work around this with the -Key parameter. From the helpful folks at PDQ.
You create an AES key like so:
$KeyFile = "C:\AES.key"
$Key = New-Object Byte[] 16 # You can use 16 (128-bit), 24 (192-bit), or 32 (256-bit) for AES
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | Out-File $KeyFile
Create the new SecureString object:
$PasswordFile = "C:\Password.txt"
$KeyFile = "C:\AES.key"
$Key = Get-Content $KeyFile
$Password = "P#ssword1" | ConvertTo-SecureString -AsPlainText -Force
$Password | ConvertFrom-SecureString -key $Key | Out-File $PasswordFile
Creating PSCredential object on another computer or user:
$User = "MyUserName"
$PasswordFile = "C:\Password.txt"
$KeyFile = "C:\AES.key"
$key = Get-Content $KeyFile
$MyCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)
Anyone who gets the AES.key file will be able to decrypt the SecureString object so be mindful can access it!

Powershell data read from file contains dollar sign $

I have a powershell script that is reading a password from a file, the password has been 'secured' using a generated AES Key. There are three files used in the process
AES Key File Generation:
$KeyFile = "\\server\path\AES.key"
$Key = New-Object Byte[] 16
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | out-file $KeyFile
Password File Generation:
$PasswordFile = "\\server\path\Password.txt"
$KeyFile = "\\server\path\AES.key"
$Key = Get-Content $KeyFile
$Password = "Sy$tem#dmin" | ConvertTo-SecureString -AsPlainText -Force
$Password | ConvertFrom-SecureString -key $Key | Out-File $PasswordFile
Script That Grabs Password File and Converts back to Plain Text:
$User = "myuser"
$PasswordFile = "\\server\path\Password.txt"
$KeyFile = "\\server\path\AES.key"
$key = Get-Content $KeyFile
$MyCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)
$PlainPassword2 = $MyCredential.GetNetworkCredential().Password
$PlainPassword2
The conversion back to plain text is really being done just so we can verify that the data is the same as what was initially created.
When we display the data contained in $PlainPassword2 instead of seeing Sy$tem#dmin as is expected, we are seeing Sy#dmin.
What can we do to correct this?
You are using double-quotes when converting the original password string:
$Password = "Sy$tem#dmin" | ConvertTo-SecureString -AsPlainText -Force
Since " allow for string interpolation, the parser tries to expand $tem, which, since it probably doesn't exist results in an empty string, thus you end up with the string you see in your output.
Use single-quotes instead:
$Password = 'Sy$tem#dmin' | ConvertTo-SecureString -AsPlainText -Force

Encrypt Credentials, Export, then Import

I've been working with Powershell for quite some time now but I don't understand how the encryption works, not even sure I'm using the right syntax from reading the help files.
#Get User Information
$User = Read-Host "Please enter your username"
$Password = Read-Host "Please enter your password. This will be encrypted" -AsSecureString | ConvertTo-SecureString -AsPlainText -Force
#Define a Key File
$KeyFile = "C:\Powershell\AES.key"
$Key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | out-file $KeyFile
#Encrypt using AES
$PasswordFile = "C:\Powershell\Password.txt"
$KeyFile = "C:\Powershell\AES.key"
$Key = Get-Content $KeyFile
$Password | ConvertFrom-SecureString | Out-File $PasswordFile
#Set credentials to be called.
$myCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)
#Open text file.
Invoke-Command -ComputerName localhost -Credential $MyCredentials -ScriptBlock{
Invoke-Item C:\Powershell\Password.txt
}
I received an error when running this and I'm not sure why I can't pipe this:
ConvertFrom-SecureString : The input object cannot be bound to any
parameters for the command either because the command does not take
pipeline input or the input and its properties do not match any of the
parameters that take pipeline input. At C:\Powershell\Password.ps1:15
char:13
+ $Password | ConvertFrom-SecureString -Key $Key | Out-File $PasswordFile
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.Security.SecureString:String) [ConvertFrom-SecureString],
ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.ConvertFromSecureStringCommand
Are there any encryption experts that can help? I'm trying to simply save a password to a text file (encrypted) and then I want to use another script to call various programs using new credentials using the encrypted password, but I can't even get the encrypted password to work correctly. Thanks in advance.
To make things simple:
To Save the Credential Object to disk:
$credential = Get-Credential
$Key = [byte]1..32
$credential.Password | ConvertFrom-SecureString -Key $Key | Set-Content c:\cred.key
To Load it back to Powershell:
$Key = [byte]1..32
$username = "type the username here"
$encrypted = Get-Content c:\cred.key | ConvertTo-SecureString -Key $Key
## Create The Credential Object:
$credential = New-Object System.Management.Automation.PsCredential($username, $encrypted)
Sure that this is not secured, because everyone who see your code can re-use the credential,
If you are not using a key at all, the credential will be encrypted with your current user, and only the current user can decrypt it back.