Skip to content

Commit

Permalink
Changes to work on PSCore Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
jborean93 committed Dec 2, 2019
1 parent a50b917 commit 71d5deb
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 68 deletions.
35 changes: 33 additions & 2 deletions AnsibleVault/Private/New-PBKDF2Key.ps1
@@ -1,4 +1,4 @@
# Copyright: (c) 2018, Jordan Borean (@jborean93) <jborean93@gmail.com>
# Copyright: (c) 2018, Jordan Borean (@jborean93) <jborean93@gmail.com>
# MIT License (see LICENSE or https://opensource.org/licenses/MIT)

Function New-PBKDF2Key {
Expand Down Expand Up @@ -61,6 +61,37 @@ Function New-PBKDF2Key {
[Parameter(Mandatory=$true)] [UInt64]$Iterations
)

# Rfc2898DeriveBytes only allowed a custom hash algorithm in 4.6 or newer. We check to see whether the enum is
# available and fallback to PInvoking.
try {
$null = [System.Security.Cryptography.HashAlgorithmName]
$use_dotnet = $true
} catch [System.Management.Automation.RuntimeException] {
$use_dotnet = $false
}

if ($use_dotnet) {
$algo = [System.Security.Cryptography.HashAlgorithmName]$Algorithm
$pass_ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($Password)
try {
$pass_str = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($pass_ptr)
$provider = New-Object -TypeName System.Security.Cryptography.Rfc2898DeriveBytes -ArgumentList @(
$pass_str,
$Salt,
$Iterations,
$algo
)
try {
return $provider.GetBytes($Length)
} finally {
$provider.Dispose()
}
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($pass_ptr)
}
}

# Rfc2898DeriveBytes not available on older platforms, rely on PInvoke for this step.
$return_codes = @{
"3221225485" = "An invalid parameter was passed to a service or function (STATUS_INVALID_PARAMETER 0xC0000000D)"
"3221225480" = "An invalid HANDLE was specified (STATUS_INVALID_HANDLE 0xC0000008)"
Expand Down Expand Up @@ -128,4 +159,4 @@ Function New-PBKDF2Key {
}

return [byte[]]$key
}
}
4 changes: 2 additions & 2 deletions Tests/Add-Pkcs7Padding.Tests.ps1
Expand Up @@ -5,8 +5,8 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand Down
4 changes: 2 additions & 2 deletions Tests/Convert-ByteToHex.Tests.ps1
Expand Up @@ -5,8 +5,8 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand Down
4 changes: 2 additions & 2 deletions Tests/Convert-HexToByte.Tests.ps1
Expand Up @@ -5,8 +5,8 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand Down
38 changes: 11 additions & 27 deletions Tests/Get-DecryptedAnsibleVault.Tests.ps1
@@ -1,4 +1,4 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Need to create secure string from samples in tests")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Need to create secure string from samples in tests")]
param()

$verbose = @{}
Expand All @@ -8,7 +8,7 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand All @@ -17,39 +17,23 @@ Describe "$module_name PS$ps_version tests" {
It "Can decrypt vault <Vault> with password <VaultSecret>" -TestCases @(
@{ Vault = "small_1.1"; VaultSecret = 'password' }
@{ Vault = "large_1.1"; VaultSecret = 'Ye^wS##X9qAC4lHDY^ajMvZ*IZrv47Px^hv2#&a8#$KncjKK^T8eJGWcH&Q@yaj4J7rP%ktyMeYTx!ZU2Ce&GeT$$vmSWRq4fqvs' }
@{
Vault = "unicode_1.1";
# Due to unique encoding issues with the test and PowerShell
# we revert to storing the password as a byte array and setting
# that as the secure string at runtime
VaultSecret = [byte[]]@(
195, 162, 194, 157, 197, 146, 195, 162,
197, 190, 226, 128, 147, 195, 162, 197,
190, 226, 128, 162, 195, 162, 197, 190,
226, 128, 147, 195, 162, 197, 190, 226,
128, 162, 195, 162, 197, 190, 226, 128,
147, 195, 162, 194, 173, 226, 128, 162)
}
@{ Vault = "unicode_1.1"; VaultSecret = '❌➖➕➖➕➖⭕' }
@{ Vault = "dev_1.2"; VaultSecret = 'WsT2Wf!MnHctYXIQbI%xr$L8aid@fLTS6tA*' }
) {
param ($Vault, $VaultSecret)

if ($VaultSecret -is [byte[]]) {
$VaultSecret = [System.Text.Encoding]::UTF8.GetString($VaultSecret)
}

$vault_contents = Get-Content -Path "$PSScriptRoot\Resources\$Vault.vault" -Raw
$expected = (Get-Content -Path "$PSScriptRoot\Resources\$Vault.yml" -Raw).Replace("`r`n", "`n")
$vault_contents = Get-Content -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', "$($Vault).vault")) -Raw
$expected = (Get-Content -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', "$($Vault).yml")) -Raw).Replace("`r`n", "`n")
$password = ConvertTo-SecureString -String $VaultSecret -AsPlainText -Force

$actual = Get-DecryptedAnsibleVault -Value $vault_contents -Password $password
$actual | Should -Be $expected

$actual = Get-DecryptedAnsibleVault -Path "$PSScriptRoot\Resources\$Vault.vault" -Password $password
$actual = Get-DecryptedAnsibleVault -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', "$($Vault).vault")) -Password $password
$actual | Should -Be $expected

# repeat again and make sure omitting -Path is for the path to a vault file
$actual = Get-DecryptedAnsibleVault "$PSScriptRoot\Resources\$Vault.vault" -Password $password
$actual = Get-DecryptedAnsibleVault ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', "$($Vault).vault")) -Password $password
$actual | Should -Be $expected

$actual = $vault_contents | Get-DecryptedAnsibleVault -Password $password
Expand All @@ -58,9 +42,9 @@ Describe "$module_name PS$ps_version tests" {
It "Can decrypt vault file in pwd not absolute path" {
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$previous_pwd = (Get-Location).Path
Set-Location -Path $PSScriptRoot\Resources
Set-Location -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources'))

$expected = (Get-Content -Path "$PSScriptRoot\Resources\small_1.1.yml" -Raw).Replace("`r`n", "`n")
$expected = (Get-Content -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', 'small_1.1.yml')) -Raw).Replace("`r`n", "`n")
$actual = Get-DecryptedAnsibleVault -Path "small_1.1.vault" -Password $password
Set-Location -Path $previous_pwd
$actual | Should -Be $expected
Expand All @@ -78,7 +62,7 @@ Describe "$module_name PS$ps_version tests" {
) {
param ($Version)

$vault_contents = Get-Content -Path "$PSScriptRoot\Resources\small_1.1.vault" -Raw
$vault_contents = Get-Content -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', 'small_1.1.vault')) -Raw
$vault_contents = "`$ANSIBLE_VAULT;$Version;AES256`n" + $vault_contents.Substring(31)

$password = ConvertTo-SecureString -String "pass" -AsPlainText -Force
Expand All @@ -87,7 +71,7 @@ Describe "$module_name PS$ps_version tests" {
}

It "Throw exception on invalid password" {
$vault_contents = Get-Content -Path "$PSScriptRoot\Resources\small_1.1.vault" -Raw
$vault_contents = Get-Content -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', 'small_1.1.vault')) -Raw
$password = ConvertTo-SecureString -String "invalid_pass" -AsPlainText -Force
{ Get-DecryptedAnsibleVault -Value $vault_contents -Password $password } |
Should -Throw "HMAC verification failed, was the wrong password entered?"
Expand Down
8 changes: 4 additions & 4 deletions Tests/Get-EncryptedAnsibleVault.Tests.ps1
Expand Up @@ -8,7 +8,7 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand All @@ -22,7 +22,7 @@ Describe "$module_name PS$ps_version tests" {
) {
param ($Vault, $VaultSecret)

$path = "$PSScriptRoot\Resources\$Vault.yml"
$path = [System.IO.Path]::Combine($PSScriptRoot, 'Resources', "$($Vault).yml")
$plaintext = (Get-Content -Path $path -Raw).Replace("`r`n", "`n")
$password = ConvertTo-SecureString -String $VaultSecret -AsPlainText -Force

Expand Down Expand Up @@ -85,13 +85,13 @@ Describe "$module_name PS$ps_version tests" {
It "Can encrypt a vault file in the pwd" {
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$previous_pwd = (Get-Location).Path
Set-Location -Path $PSScriptRoot\Resources
Set-Location -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources'))

$actual = Get-EncryptedAnsibleVault -Path "small_1.1.yml" -Password $password
Set-Location -Path $previous_pwd
$actual | Should -BeLike '$ANSIBLE_VAULT;1.1;AES256*'
$dec_actual = $actual | Get-DecryptedAnsibleVault -Password $password
$dec_actual | Should -Be (Get-Content -Path "$PSScriptRoot\Resources\small_1.1.yml" -Raw)
$dec_actual | Should -Be (Get-Content -Path ([System.IO.Path]::Combine($PSScriptRoot, 'Resources', 'small_1.1.yml')) -Raw)
}
}
}
8 changes: 4 additions & 4 deletions Tests/Get-HMACValue.Tests.ps1
Expand Up @@ -5,10 +5,10 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
. $PSScriptRoot\..\AnsibleVault\Private\Convert-HexToByte.ps1
. $PSScriptRoot\..\AnsibleVault\Private\Convert-ByteToHex.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "Convert-HexToByte.ps1"))
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "Convert-ByteToHex.ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand Down
6 changes: 3 additions & 3 deletions Tests/Get-VaultHeader.Tests.ps1
Expand Up @@ -5,9 +5,9 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
. $PSScriptRoot\..\AnsibleVault\Private\Convert-HexToByte.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "Convert-HexToByte.ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand Down
6 changes: 3 additions & 3 deletions Tests/Invoke-AESCTRCycle.Tests.ps1
Expand Up @@ -5,9 +5,9 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
. $PSScriptRoot\..\AnsibleVault\Private\Convert-HexToByte.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "Convert-HexToByte.ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand Down
12 changes: 8 additions & 4 deletions Tests/Invoke-Win32Api.Tests.ps1
Expand Up @@ -3,10 +3,14 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")
$verbose.Add("Verbose", $true)
}

# Tests won't run on Linux so skip
$is_windows = Get-Variable -Name IsWindows -ErrorAction SilentlyContinue
$skip = $null -ne $is_windows -and $is_windows.Value -eq $false

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))

Describe "$module_name PS$ps_version tests" {
Context 'Strict mode' {
Expand All @@ -16,7 +20,7 @@ Describe "$module_name PS$ps_version tests" {
{ Invoke-Win32Api -DllName a.dll -MethodName a -ReturnType bool -ParameterTypes @([int]) -Parameters @() } | Should -Throw "ParameterType Count 1 not equal to Parameter Count 0"
}

It 'invoke API that returns a handle' {
It 'invoke API that returns a handle' -Skip:$skip {
$test_file_path = "$PSScriptRoot\Resources\test-deleteme.txt"
if (-not (Test-Path -Path $test_file_path)) {
New-Item -Path $test_file_path -ItemType File > $null
Expand Down Expand Up @@ -54,7 +58,7 @@ Describe "$module_name PS$ps_version tests" {
}
}

It 'invoke API with output strings' {
It 'invoke API with output strings' -Skip:$skip {
$sid_string = "S-1-5-18"
$sid = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $sid_string
$sid_bytes = New-Object -TypeName byte[] -ArgumentList $sid.BinaryLength
Expand Down
33 changes: 27 additions & 6 deletions Tests/New-PBKDF2Key.Tests.ps1
@@ -1,4 +1,5 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Need to create secure string from samples in tests")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingEmptyCatchBlock", "", Justification="Need to detect the .NET version for Salt length skipping")]
param()

$verbose = @{}
Expand All @@ -8,10 +9,10 @@ if ($env:APPVEYOR_REPO_BRANCH -and $env:APPVEYOR_REPO_BRANCH -notlike "master")

$ps_version = $PSVersionTable.PSVersion.Major
$module_name = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "")
Import-Module -Name $PSScriptRoot\..\AnsibleVault -Force
. $PSScriptRoot\..\AnsibleVault\Private\$module_name.ps1
. $PSScriptRoot\..\AnsibleVault\Private\Convert-ByteToHex.ps1
. $PSScriptRoot\..\AnsibleVault\Private\Invoke-Win32Api.ps1
Import-Module -Name ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault')) -Force
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "$($module_name).ps1"))
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "Convert-HexToByte.ps1"))
. ([System.IO.Path]::Combine($PSScriptRoot, '..', 'AnsibleVault', 'Private', "Invoke-Win32Api.ps1"))


Describe "$module_name PS$ps_version tests" {
Expand Down Expand Up @@ -120,6 +121,14 @@ Describe "$module_name PS$ps_version tests" {
){
param($Algorithm, $Secret, $Salt, $Iterations, $Length, $Expected)

try {
# .NET Fails if the Salt is less than 8 chars even though it is valid, just need to skip those tests
[System.Security.Cryptography.HashAlgorithmName] > $null
if ($Salt.Length -lt 8) {
return
}
} catch [System.Management.Automation.RuntimeException] {}

$sec_pass = ConvertTo-SecureString -String $Secret -AsPlainText -Force
$salt_bytes = [System.Text.Encoding]::UTF8.GetBytes($Salt)
$actual = New-PBKDF2Key -Algorithm $Algorithm `
Expand All @@ -133,12 +142,24 @@ Describe "$module_name PS$ps_version tests" {

It 'fail with invalid algorithm' {
$sec_pass = ConvertTo-SecureString -String "a" -AsPlainText -Force
{ New-PBKDF2Key -Algorithm "fake" -Password $sec_pass -Salt ([byte[]]@(1)) -Length 1 -Iterations 0 } | Should -Throw "Failed to open algorithm provider with ID 'fake': The object was not found (STATUS_NOT_FOUND 0xC0000225)"
try {
[System.Security.Cryptography.HashAlgorithmName] > $null
$expected = "'fake' is not a known hash algorithm"
} catch [System.Management.Automation.RuntimeException] {
$expected = "Failed to open algorithm provider with ID 'fake': The object was not found (STATUS_NOT_FOUND 0xC0000225)"
}
{ New-PBKDF2Key -Algorithm "fake" -Password $sec_pass -Salt ([byte[]]@(1, 2, 3, 4, 5, 6, 7, 8)) -Length 1 -Iterations 1 } | Should -Throw $expected
}

It 'failed to generate key with invalid parameters' {
$sec_pass = ConvertTo-SecureString -String "a" -AsPlainText -Force
{ New-PBKDF2Key -Algorithm SHA256 -Password $sec_pass -Salt ([byte[]]@(1)) -Length 0 -Iterations 0 } | Should -Throw "Failed to derive key: An invalid parameter was passed to a service or function (STATUS_INVALID_PARAMETER 0xC0000000D)"
try {
[System.Security.Cryptography.HashAlgorithmName] > $null
$expected = "Positive number required"
} catch [System.Management.Automation.RuntimeException] {
$expected = "Failed to derive key: An invalid parameter was passed to a service or function (STATUS_INVALID_PARAMETER 0xC0000000D)"
}
{ New-PBKDF2Key -Algorithm SHA256 -Password $sec_pass -Salt ([byte[]]@(1, 2, 3, 4, 5, 6, 7, 8)) -Length 1 -Iterations 0 } | Should -Throw $expected
}
}
}

0 comments on commit 71d5deb

Please sign in to comment.