public/Protect-GzBlob.ps1



function Protect-GzBlob() {

    [CmdletBinding()]
    Param(
        [Parameter(Position = 0, ValueFromPipeline = $true )]
        [Byte[]] $Blob,


        [Parameter(ParameterSetName = "PrivateKey")]
        [Byte[]] $PrivateKey,

        [Parameter(ParameterSetName = "Password")]
        [SecureString] $Password,

        [Parameter(ParameterSetName = "Keys")]
        [Byte[]] $Key,

        [Parameter(ParameterSetName = "Keys")]
        [Byte[]] $AuthenticationKey,

        [Alias("Headers")]
        [Byte[]] $InsecureInfo
    )

    PROCESS {

        $aes = [System.Security.Cryptography.Aes]::Create()
        $options = Get-GzProtectDataOption
        $aes.KeySize = $options.KeySize
        $aes.BlockSize = $options.BlockSize
        $aes.Mode = "CBC"
        $aes.Padding = "PKCS7"
    
        $Headers = $InsecureInfo
        if(!$Headers) {
            $Headers = New-Object 'Byte[]' -ArgumentList 0
        }
        $headerSize = ($options.SaltSize / 8) * 2
        $headerSize = $headerSize + $Headers.Length
        $header = New-Object 'byte[]' -ArgumentList $headerSize
        [Array]::Copy($headers, $header, $headers.Length)
        $headerIndex = $Headers.Length
    
        $aes.GenerateIV();
        $iv = $aes.IV
        if($Password -or $PrivateKey) {
            if($Password) {
                $PrivateKey = $Password  | ConvertTo-UnprotectedBytes 
            }
            
            $salt = New-ProtectBlobSalt -SaltSize $options.SaltSize
           
            $generator = New-Object System.Security.Cryptography.Rfc2898DeriveBytes `
                -ArgumentList $PrivateKey, $salt, ($options.Iterations)
            $salt = $generator.Salt
          
            $Key = $generator.GetBytes($options.KeySize / 8)
    
            [Array]::Copy($salt, 0, $header, $headerIndex, $salt.Length)
            $headerIndex += $salt.Length
            $generator.Dispose()
    
            $salt = New-ProtectBlobSalt -SaltSize $options.SaltSize
            $generator = New-Object System.Security.Cryptography.Rfc2898DeriveBytes `
                -ArgumentList $PrivateKey, $salt, ($options.Iterations)
            $salt = $generator.Salt
    
            $AuthenticationKey = $generator.GetBytes($options.KeySize / 8)
    
            [Array]::Copy($salt, 0, $header, $headerIndex, $salt.Length)
            $headerIndex += $salt.Length
            $generator.Dispose()
    
            [Array]::Clear($salt, 0, $salt.Length)
        }
    
        if(!$Key -or $Key.Length -eq 0) {
            Throw [ArgumentException] "Key must not be null or empty"
        }
    
        if(!$AuthenticationKey -or $AuthenticationKey.Length -eq 0) {
            Throw [ArgumentException] "AuthenticationKey must not be null or empty"
        }
    
        $encryptor = $aes.CreateEncryptor($key, $iv)
        $ms = New-Object System.IO.MemoryStream
        $cryptoStream = New-Object System.Security.Cryptography.CryptoStream($ms, $encryptor, "Write")
        $binaryWriter = New-Object System.IO.BinaryWriter($cryptoStream)
    
        $binaryWriter.Write($Blob)
        $binaryWriter.Flush()
        $cryptoStream.Flush()
        $cryptoStream.FlushFinalBlock()
        $ms.Flush()
        $encryptedBlob = $ms.ToArray()
    
        $binaryWriter.Dispose()
        $cryptoStream.Dispose()
        $ms.Dispose()
    
        $hmac = New-Object System.Security.Cryptography.HMACSHA256
        $hmac.Key = $AuthenticationKey
        $ms = New-Object System.IO.MemoryStream
        $binaryWriter = New-Object System.IO.BinaryWriter($ms)
    
        try {
        
            $binaryWriter.Write($Header);
            $binaryWriter.Write($iv);
    
            $binaryWriter.Write($encryptedBlob);
            $binaryWriter.Flush()
            $ms.Flush()
            $data = $ms.ToArray()
            $hash = $hmac.ComputeHash($data)
            $binaryWriter.Write($hash);
    
            $binaryWriter.Flush()
            $ms.Flush()

           
    
            return $ms.ToArray()
        } finally {
            if($Password -or $PrivateKey) {
                [Array]::Clear($key, 0, $key.Length)
                [Array]::Clear($AuthenticationKey, 0, $AuthenticationKey.Length)
            }
           
            [Array]::Clear($iv, 0, $iv.Length)
            $binaryWriter.Dispose()
            $ms.Dispose()
            $hmac.Dispose()
        }
    }
}