Functions/EncryptionFunctions.ps1
function ConvertFrom-FIPSSecureString { <# .SYNOPSIS Converts a SecureString object into encrypted text with a FIPS compliant algorithm using a pre-shared key. The Pre-Shared key can be provided as either a 32 byte array or a SecureString value. .PARAMETER SecureString The SecureString object that will returned as an encrypted string. .PARAMETER Key An array of 32 bytes that will be used as a the pre-shared key for encryption. .PARAMETER SecureKey A SecureString that will be converted into a 32 byte array used as the pre-shared key for encryption. .EXAMPLE Encrypt a SecureString object and save it to disk $EncryptedText = ConvertFrom-FIPSSecureString -SecureString $MySecretValue -SecureKey ('Pr3$haredK3y' | Convertto-SecureString -AsPlainText -Force) $EncryptedText | Out-File ./encryptedText.txt #> [CmdletBinding()] param( [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$true,ParameterSetName="KeyByte")] [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$true,ParameterSetName="SecureKey")] [ValidateNotNullOrEmpty()] [System.Security.SecureString]$SecureString, [Parameter(Mandatory=$True,ParameterSetName="KeyByte")] [ValidateNotNullOrEmpty()] [byte[]]$Key, [Parameter(Mandatory=$True,ParameterSetName="SecureKey")] [ValidateNotNullOrEmpty()] [System.Security.SecureString]$SecureKey ) if ($PSBoundParameters.ContainsKey('SecureKey')) { $Key = Convert-SecureStringto32ByteKey -SecureString $SecureKey } if ($null -eq $Key -or $Key.GetLength(0) -ne 32) { throw "Key must be provided as a 32byte (256bit) byte array" } $BSTR = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) $dataBytes = [System.Text.Encoding]::UTF8.GetBytes([Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)) [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) $aes = New-Object -TypeName System.Security.Cryptography.AesCryptoServiceProvider $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $aes.BlockSize = 128 $aes.KeySize = 256 $aes.Key = $Key $encryptionObject = $aes.CreateEncryptor() Write-Verbose -Message "Converting SecureString to encrypted string with AESCryptoServiceProvider" [byte[]]$encryptedDataBytes = $aes.IV + ($encryptionObject.TransformFinalBlock($dataBytes,0,$dataBytes.Length)) $aes.Dispose() return [System.Convert]::ToBase64String($encryptedDataBytes) } function ConvertTo-FIPSSecureString { <# .SYNOPSIS Converts a string of encrypted text back into a SecureString object with a FIPS compliant algorithm using a pre-shared key. The Pre-Shared key can be provided as either a 32 byte array or a SecureString value. .PARAMETER EncryptedString The string of encrypted text to convert back into a SecureString object .PARAMETER Key An array of 32 bytes that will be used as a the pre-shared key for decryption. .PARAMETER SecureKey A SecureString that will be converted into a 32 byte array used as the pre-shared key for decryption. .EXAMPLE $EncryptedText = Get-Content ./encryptedText.txt $MySecret = ConvertTo-FIPSSecureString -EncryptedString $EncryptedText -SecureKey ('Pr3$haredK3y' | Convertto-SecureString -AsPlainText -Force) #> [CmdletBinding()] param( [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$true,ParameterSetName="KeyByte")] [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$true,ParameterSetName="SecureKey")] [ValidateNotNullOrEmpty()] [System.String]$EncryptedString, [Parameter(Mandatory=$True,ParameterSetName="KeyByte")] [ValidateNotNullOrEmpty()] [byte[]]$Key, [Parameter(Mandatory=$True,ParameterSetName="SecureKey")] [ValidateNotNullOrEmpty()] [System.Security.SecureString]$SecureKey ) if ($PSBoundParameters.ContainsKey('SecureKey')) { $Key = Convert-SecureStringto32ByteKey -SecureString $SecureKey } if ($null -eq $Key -or $Key.GetLength(0) -ne 32) { throw "Key must be provided as a 32byte (256bit) byte array" } $dataBytes = [System.Convert]::FromBase64String($EncryptedString) $IV = $dataBytes[0..15] $aes = New-Object -TypeName System.Security.Cryptography.AesCryptoServiceProvider $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $aes.BlockSize = 128 $aes.KeySize = 256 $aes.Key = $Key $aes.IV = $IV $decryptionObject = $aes.CreateDecryptor() Write-Verbose -Message "Converting AES encrypted string to SecureString" [byte[]]$decryptedDataBytes =$decryptionObject.TransformFinalBlock($dataBytes,16,$dataBytes.Length -16) $aes.Dispose() return ([System.Text.Encoding]::UTF8.GetString($decryptedDataBytes) | ConvertTo-SecureString -AsPlainText -Force) } function ConvertFrom-PKISecureString { <# .SYNOPSIS Converts a SecureString object into encrypted text with the public key of a PKI certificate. .PARAMETER SecureString The SecureString object that will returned as an encrypted string. .PARAMETER Thumbprint The ThumbPrint of a certificate on the local computer that will be used to encrypt the string. .PARAMETER CertificateFile Path to a .CER certificate public key file that will be used to encrypt the string. .PARAMETER CertificateStore Specifies the certifcate store of the specified certificate thumbprint. Either LocalMachine or CurrentUser. .EXAMPLE Encrypt a SecureString object and save it to disk $EncryptedText = ConvertFrom-PKISecureString -SecureString $MySecretValue -Thumbprint '87BB70A19A7671D389F49AF4C9608B2F381FDD80' $EncryptedText | Out-File ./encryptedText.txt #> [CmdletBinding()] param( [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$True,ParameterSetName="Thumbprint")] [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$True,ParameterSetName="CertFile")] [ValidateNotNullOrEmpty()] [System.Security.SecureString]$SecureString, [Parameter(Mandatory=$true,ParameterSetName="Thumbprint")] [ValidateNotNullOrEmpty()] [System.String]$Thumbprint, [Parameter(Mandatory=$True,ParameterSetName="CertFile")] [ValidateScript({test-path $_})] [System.String]$CertificateFile, [Parameter(Mandatory=$False,ParameterSetName="Thumbprint")] [ValidateSet("CurrentUser","LocalMachine")] [System.String]$CertificateStore ) $BSTR = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) $dataBytes = [System.Text.Encoding]::UTF8.GetBytes([Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)) [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) if ($PSCmdlet.ParameterSetName -eq "CertFile") { $Certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2($CertificateFile) if ($null -eq $Certificate.Thumbprint) { throw "$CertificateFile does not appear to be a valid x509 certificate file" } } else { if ($PSBoundParameters.ContainsKey('CertificateStore')) { $Certificate = Get-Item "Cert:\$CertificateStore\My\$Thumbprint" -ErrorAction "SilentlyContinue" #error checking if ($null -eq $Certificate.Thumbprint) { throw "Could not find a valid certificate in the $CertificateStore store with thumbprint $Thumbprint" } } else { #first look in CurrentUser $Certificate = Get-Item "Cert:\CurrentUser\My\$Thumbprint" -ErrorAction "Silentlycontinue" if ($null -eq $Certificate.Thumbprint) { #nothing in CurrentUser, try LocalMachine $Certificate = Get-Item "Cert:\LocalMachine\My\$Thumbprint" -ErrorAction "Silentlycontinue" } #error checking if ($null -eq $Certificate.Thumbprint) { throw "Could not find a valid certificate in the CurrentUser or LocalMachine store with thumbprint $Thumbprint" } } } Write-Verbose "Converting SecureString to encrypted string with certificate thumbprint $($Certificate.Thumbprint)" $EncryptedBytes = $Certificate.PublicKey.Key.Encrypt($dataBytes,$True) return [Convert]::ToBase64String($EncryptedBytes) } function ConvertTo-PKISecureString { <# .SYNOPSIS Converts a string of encrypted text back into a SecureString object with the private key of a PKI certificate. .PARAMETER EncryptedString The string of encrypted text to convert back into a SecureString object .PARAMETER Thumbprint The ThumbPrint of a certificate on the local computer that will be used to decrypt the string. .PARAMETER CertificateStore Specifies the certifcate store of the specified certificate thumbprint. Either LocalMachine or CurrentUser. .EXAMPLE Read an encrypted string from disk and decrypt it back into a SecureString $EncryptedText = Get-Content ./encryptedText.txt $MySecretValue = ConvertTo-PKISecureString -EncryptedString $EncryptedValue -Thumbprint '87BB70A19A7671D389F49AF4C9608B2F381FDD80' #> [CmdletBinding()] param( [Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$True)] [ValidateNotNullOrEmpty()] [System.String]$EncryptedString, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String]$Thumbprint, [Parameter(Mandatory=$False)] [ValidateSet("CurrentUser","LocalMachine")] [System.String]$CertificateStore ) if ($PSBoundParameters.ContainsKey('CertificateStore')) { $Certificate = Get-Item "Cert:\$CertificateStore\My\$Thumbprint" -ErrorAction "SilentlyContinue" #error checking if ($null -eq $Certificate.Thumbprint) { throw "Could not find a valid certificate in the $CertificateStore store with thumbprint $Thumbprint" } } else { #first look in CurrentUser $Certificate = Get-Item "Cert:\CurrentUser\My\$Thumbprint" -ErrorAction "Silentlycontinue" if ($null -eq $Certificate.Thumbprint) { #nothing in CurrentUser, try LocalMachine $Certificate = Get-Item "Cert:\LocalMachine\My\$Thumbprint" -ErrorAction "Silentlycontinue" } #error checking if ($null -eq $Certificate.Thumbprint) { throw "Could not find a valid certificate in the CurrentUser or LocalMachine store with thumbprint $Thumbprint" } } Write-Verbose "Converting encrypted string to SecureString with certificate thumbprint $($Certificate.Thumbprint)" $EncryptedBytes = [Convert]::FromBase64String($EncryptedString) return ([System.Text.Encoding]::UTF8.GetString($Certificate.PrivateKey.Decrypt($EncryptedBytes,$True)) | ConvertTo-SecureString -AsPlainText -Force) } |