Private/Invoke-AESCTRCycle.ps1
# Copyright: (c) 2018, Jordan Borean (@jborean93) <jborean93@gmail.com> # MIT License (see LICENSE or https://opensource.org/licenses/MIT) Function Invoke-AESCTRCycle { <# .SYNOPSIS Uses AES in CTR mode to encrypt/decrypt a byte array. .DESCRIPTION Uses the AES encryption mechanism in CTR block mode to transform input bytes. This function can be used to encrypt and decrypt the bytes in the Ansible Vault with relative ease. Because AES in CTR mode is a stream cipher, the input bytes does not have to be the same as the AES block size. .PARAMETER Value [byte[]] The input bytes to transform. .PARAMETER Key [byte[]] The key used to increment the nonce/counter used as part of the byte transformation process. .PARAMETER Nonce [byte[]] The nonce/counter used to XOR the input bytes and transform it to the output bytes .OUTPUTS [byte[]] The encrypted/decrypted bytes after running through a cycle. .NOTES The .NET class AesCryptoServiceProvider does not have a native CTR mode so this must be done manually. Thanks to Hans Wolff at https://gist.github.com/hanswolff/8809275, I've been able to use that code as a reference and create a PowerShell function to do the same. #> [CmdletBinding()] [OutputType([byte[]])] param( [Parameter(Mandatory=$true)] [byte[]]$Value, [Parameter(Mandatory=$true)] [byte[]]$Key, [Parameter(Mandatory=$true)] [byte[]]$Nonce ) $counter_cipher = New-Object System.Security.Cryptography.AesCryptoServiceProvider $counter_cipher.Mode = [System.Security.Cryptography.CipherMode]::ECB $counter_cipher.Padding = [System.Security.Cryptography.PaddingMode]::None $counter_encryptor = $counter_cipher.CreateEncryptor($Key, (New-Object -TypeName byte[] -ArgumentList($counter_cipher.BlockSize / 8))) $xor_mask = New-Object -TypeName System.Collections.Queue $output = New-Object -TypeName byte[] -ArgumentList $Value.Length for ($i = 0; $i -lt $Value.Length; $i++) { if ($xor_mask.Count -eq 0) { $counter_mode_block = New-Object -TypeName byte[] -ArgumentList ($counter_cipher.BlockSize / 8) $counter_encryptor.TransformBlock($Nonce, 0, $Nonce.Length, $counter_mode_block, 0) > $null for ($j = $Nonce.Length - 1; $j -ge 0; $j--) { $current_nonce_value = $Nonce[$j] if ($current_nonce_value -eq 255) { $Nonce[$j] = 0 } else { $Nonce[$j] += 1 } if ($Nonce[$j] -ne 0) { break } } foreach ($counter_byte in $counter_mode_block) { $xor_mask.Enqueue($counter_byte) } } $current_mask = $xor_mask.Dequeue() $output[$i] = [byte]($Value[$i] -bxor $current_mask) } return [byte[]]$output } |