Public/Unprotect-EncryptedFile.ps1
|
using namespace System using namespace System.IO using namespace System.Security.Cryptography using namespace System.Collections.Immutable Set-StrictMode -Version Latest #### <h2 style="color: #DCA657;">Unprotect-EncryptedFile</h2> #### function Unprotect-EncryptedFile { #### Decrypt a file produced by `Protect-FileWithEncryption`. #### #### <b style="color: #D2A8FF;">Parameters</b> #### [CmdletBinding()] param ( #### - `[string]`: __EncryptedFilePath__ #### - *Path to the `.enc` file.* [Parameter(Mandatory = $true)] [string]$EncryptedFilePath, #### - `[securestring]`: __FilePassword__ #### - *The passphrase used during encryption.* [Parameter(Mandatory = $true)] [securestring]$FilePassword, #### - `[string]`: __OutputFilePath__ #### - *Destination for the decrypted output.* [Parameter(Mandatory = $true)] [string]$OutputFilePath ) #### #### <b style="color: #C22514;">Throws</b> #### #### - When `EncryptedFilePath` does not resolve. #### - When the passphrase is wrong, which surfaces as a padding failure. $EncryptedFilePath = Resolve-Path -Path $EncryptedFilePath -ErrorAction Stop try { $encryptedStream = [File]::Open($EncryptedFilePath, 'Open', 'Read') try { #### Salt and IV come off the front of the file in the order they were written. $salt = [byte[]]::new(16) $encryptedStream.Read($salt, 0, $salt.Length) | Out-Null $iv = [byte[]]::new(16) $encryptedStream.Read($iv, 0, $iv.Length) | Out-Null $pbkdf2 = [Rfc2898DeriveBytes]::new($FilePassword, $salt, 100000) $key = $pbkdf2.GetBytes(32) $aes = [Aes]::Create() $aes.Key = $key $aes.IV = $iv $decryptor = $aes.CreateDecryptor() $cryptoStream = [CryptoStream]::new($encryptedStream, $decryptor, [CryptoStreamMode]::Read) $outputStream = [File]::Open($OutputFilePath, 'Create', 'Write') try { #### Copied in 4 KB chunks, so file size never drives memory use. $buffer = [byte[]]::new(4096) while (($bytesRead = $cryptoStream.Read($buffer, 0, $buffer.Length)) -gt 0) { $outputStream.Write($buffer, 0, $bytesRead) } #### #### <b style="color: #369FFF;">Returns</b> #### #### - `[PSCustomObject]` #### - `[string]`: __Status__ #### - *`Success`. Any failure throws instead.* #### - `[string]`: __EncryptedFile__ #### - *Resolved path of the input.* #### - `[string]`: __DecryptedFile__ #### - *Path of the decrypted output.* #### - `[int]`: __EncryptedFileSizeKB__ #### - *Size of the input in KB.* #### - `[int]`: __DecryptedFileSizeKB__ #### - *Size of the output in KB.* #### - `[string]`: __Salt__ #### - *Base64 salt read from the header.* #### - `[string]`: __IV__ #### - *Base64 initialization vector read from the header.* $dataObject = [PSCustomObject]@{ Status = 'Success' EncryptedFile = $EncryptedFilePath DecryptedFile = $OutputFilePath EncryptedFileSizeKB = (([FileInfo]::new($EncryptedFilePath).Length / 1KB) -as [int]) DecryptedFileSizeKB = (([FileInfo]::new($OutputFilePath).Length / 1KB) -as [int]) Salt = ([Convert]::ToBase64String($salt)) IV = ([Convert]::ToBase64String($iv)) } $dataObject } finally { $outputStream.Close() $cryptoStream.Close() } } finally { $encryptedStream.Close() } } catch { throw } } #### #### --- #### |