I wrote some code to encrypt and decrypt files with PowerShell, using AES symmetric encryption. The functions depend on the built-in AesManaged class in the .NET Framework.
When I run this script, I am getting different file hashes for the original source file and the encrypted + decrypted version of the same file. Something is changing the file during the encryption or decryption process, but I am not sure what is causing the change. Every time I run the script, the file hash of the decrypted version of the source file changes. It isn't providing me a consistent result.
Does anyone see why this code would be messing with the file contents during encryption or decryption?
function Encrypt-File {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[byte[]] $Key,
# Path to the file that will be encrypted
[Parameter(Mandatory = $true)]
[string] $Path,
# Path to the resulting encrypted file
[string] $Destination
)
if (-not $PSBoundParameters['Destination']) {
$Destination = (Resolve-Path -Path $Path).Path + '.encrypted'
}
$AES = [System.Security.Cryptography.AesManaged]::new()
if ($PSBoundParameters['Key']) { $AES.Key = $Key }
$Encryptor = $AES.CreateEncryptor()
Write-Verbose -Message 'Reading source file'
$FileStream = [System.IO.FileStream]::new($Path, [System.IO.FileMode]::OpenOrCreate)
$FileWriter = [System.IO.File]::OpenWrite($Destination)
$CryptoStream = [System.Security.Cryptography.CryptoStream]::new($FileWriter, $Encryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)
Write-Verbose -Message 'Created CryptoStream'
$FileStream.CopyTo($CryptoStream)
Write-Verbose -Message 'Finished writing bytes to CryptoStream'
$AES.Key | Set-Content -Path ($Path + '.encrypted.key') -AsByteStream
$CryptoStream.Flush()
$CryptoStream.FlushFinalBlock()
$FileWriter.Flush()
$CryptoStream.Clear()
$FileWriter.Close()
$FileStream.Close()
}
function Decrypt-File {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[string] $KeyPath,
# Path to the file that will be decrypted
[Parameter(Mandatory = $true)]
[string] $Path,
# Path to the decrypted file
[string] $Destination
)
if (!$PSBoundParameters['KeyPath']) { $KeyPath = $Path + '.key' }
if (!$PSBoundParameters['Destination']) { $Destination = $Path + '.decrypted' }
$AES = [System.Security.Cryptography.AesManaged]::new()
$AES.Key = Get-Content -AsByteStream -Path $KeyPath
$Decryptor = $AES.CreateDecryptor()
$EncryptedFile = [System.IO.File]::OpenRead($Path)
$DecryptedFile = [System.IO.File]::OpenWrite($Destination)
$CryptoStream = [System.Security.Cryptography.CryptoStream]::new($DecryptedFile, $Decryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)
$EncryptedFile.CopyTo($CryptoStream)
$CryptoStream.Flush()
$DecryptedFile.Flush()
$EncryptedFile.Flush()
$CryptoStream.Clear()
$EncryptedFile.Close()
$DecryptedFile.Close()
}
$SourceFile = "$HOME/deadcat.m4a"
$EncryptedFile = "$HOME/deadcat.m4a.encrypted"
$DecryptedFile = "$HOME/deadcat.m4a.decrypted"
# Encrypt and then decrypt the file
Encrypt-File -Path $SourceFile -Verbose
Decrypt-File -Path $EncryptedFile -Verbose
# Original source file and decrypted file should both match
Get-FileHash -Path $HOME/deadcat.m4a
Get-FileHash -Path $DecryptedFile