Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
# Copyright: (c) 2018, Jordan Borean (@jborean93) <>
# MIT License (see LICENSE or
Function Invoke-AESCTRCycle {
Uses AES in CTR mode to encrypt/decrypt a byte array.
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.
[byte[]] The input bytes to transform.
[byte[]] The key used to increment the nonce/counter used as part of the
byte transformation process.
[byte[]] The nonce/counter used to XOR the input bytes and transform it to
the output bytes
[byte[]] The encrypted/decrypted bytes after running through a cycle.
The .NET class AesCryptoServiceProvider does not have a native
CTR mode so this must be done manually. Thanks to Hans Wolff at, I've been able to use that code
as a reference and create a PowerShell function to do the same.
[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) {
foreach ($counter_byte in $counter_mode_block) {
$current_mask = $xor_mask.Dequeue()
$output[$i] = [byte]($Value[$i] -bxor $current_mask)
return [byte[]]$output