From 1d3ae55c867bb0834253769dbb6eddd0a92ca198 Mon Sep 17 00:00:00 2001 From: Markus Fleschutz Date: Sat, 2 Jan 2021 14:24:22 +0100 Subject: [PATCH] Added first module --- Modules/FileCryptography.psm1 | 401 ++++++++++++++++++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 Modules/FileCryptography.psm1 diff --git a/Modules/FileCryptography.psm1 b/Modules/FileCryptography.psm1 new file mode 100644 index 00000000..0b2cfd71 --- /dev/null +++ b/Modules/FileCryptography.psm1 @@ -0,0 +1,401 @@ +function New-CryptographyKey() +{ +<# +.SYNOPSIS +Generates a random cryptography key. + +.DESCRIPTION +Generates a random cryptography key based on the desired key size. + +.PARAMETER Algorithm +Algorithm to generate key for. + +.PARAMETER KeySize +Number of bits the generated key will have. + +.PARAMETER AsPlainText +Returns a String instead of SecureString. + +.OUTPUTS +System.Security.SecureString. New-CryptographyKey return the key as a SecureString by default. +System.String. New-CryptographyKey will return the key in plain text as a string if the -AsPlainText parameter is specified. + +.EXAMPLE +$key = New-CryptographyKey +This example generates a random 256-bit AES key and stores it in the variable $key. + +.NOTES +Author: Tyler Siegrist +Date: 9/22/2017 +#> +[CmdletBinding()] +[OutputType([System.Security.SecureString])] +[OutputType([String], ParameterSetName='PlainText')] +Param( + [Parameter(Mandatory=$false, Position=1)] + [ValidateSet('AES','DES','RC2','Rijndael','TripleDES')] + [String]$Algorithm='AES', + [Parameter(Mandatory=$false, Position=2)] + [Int]$KeySize, + [Parameter(ParameterSetName='PlainText')] + [Switch]$AsPlainText +) + Process + { + try + { + $Crypto = [System.Security.Cryptography.SymmetricAlgorithm]::Create($Algorithm) + if($PSBoundParameters.ContainsKey('KeySize')){ + $Crypto.KeySize = $KeySize + } + $Crypto.GenerateKey() + if($AsPlainText) + { + return [System.Convert]::ToBase64String($Crypto.Key) + } + else + { + return [System.Convert]::ToBase64String($Crypto.Key) | ConvertTo-SecureString -AsPlainText -Force + } + } + catch + { + Write-Error $_ + } + + } +} + +Function Protect-File +{ +<# +.SYNOPSIS +Encrypts a file using a symmetrical algorithm. + +.DESCRIPTION +Encrypts a file using a symmetrical algorithm. + +.PARAMETER FileName +File(s) to be encrypted. + +.PARAMETER Key +Cryptography key as a SecureString to be used for encryption. + +.PARAMETER KeyAsPlainText +Cryptography key as a String to be used for encryption. + +.PARAMETER CipherMode +Specifies the block cipher mode to use for encryption. + +.PARAMETER PaddingMode +Specifies the type of padding to apply when the message data block is shorter than the full number of bytes needed for a cryptographic operation. + +.PARAMETER Suffix +Suffix of the encrypted file to be removed. + +.PARAMETER RemoveSource +Removes the source (decrypted) file after encrypting. + +.OUTPUTS +System.IO.FileInfo. Protect-File will return FileInfo with the SourceFile, Algorithm, Key, CipherMode, and PaddingMode as added NoteProperties + +.EXAMPLE +Protect-File 'C:\secrets.txt' $key +This example encrypts C:\secrets.txt using the key stored in the variable $key. The encrypted file would have the default extension of '.AES' and the source (decrypted) file would not be removed. + +.EXAMPLE +Protect-File 'C:\secrets.txt' -Algorithm DES -Suffix '.Encrypted' -RemoveSource +This example encrypts C:\secrets.txt with a randomly generated DES key. The encrypted file would have an extension of '.Encrypted' and the source (decrypted) file would be removed. + +.EXAMPLE +Get-ChildItem 'C:\Files' -Recurse | Protect-File -Algorithm AES -Key $key -RemoveSource +This example encrypts all of the files under the C:\Files directory using the key stored in the variable $key. The encrypted files would have the default extension of '.AES' and the source (decrypted) files would be removed. + +.NOTES +Author: Tyler Siegrist +Date: 9/22/2017 +#> +[CmdletBinding(DefaultParameterSetName='SecureString')] +[OutputType([System.IO.FileInfo[]])] +Param( + [Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] + [Alias('PSPath','LiteralPath')] + [string[]]$FileName, + [Parameter(Mandatory=$false, Position=2)] + [ValidateSet('AES','DES','RC2','Rijndael','TripleDES')] + [String]$Algorithm = 'AES', + [Parameter(Mandatory=$false, Position=3, ParameterSetName='SecureString')] + [System.Security.SecureString]$Key = (New-CryptographyKey -Algorithm $Algorithm), + [Parameter(Mandatory=$true, Position=3, ParameterSetName='PlainText')] + [String]$KeyAsPlainText, + [Parameter(Mandatory=$false, Position=4)] + [System.Security.Cryptography.CipherMode]$CipherMode, + [Parameter(Mandatory=$false, Position=5)] + [System.Security.Cryptography.PaddingMode]$PaddingMode, + [Parameter(Mandatory=$false, Position=6)] + [String]$Suffix = ".$Algorithm", + [Parameter()] + [Switch]$RemoveSource +) + Begin + { + #Configure cryptography + try + { + if($PSCmdlet.ParameterSetName -eq 'PlainText') + { + $Key = $KeyAsPlainText | ConvertTo-SecureString -AsPlainText -Force + } + + #Decrypt cryptography Key from SecureString + $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Key) + $EncryptionKey = [System.Convert]::FromBase64String([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)) + + $Crypto = [System.Security.Cryptography.SymmetricAlgorithm]::Create($Algorithm) + if($PSBoundParameters.ContainsKey('CipherMode')){ + $Crypto.Mode = $CipherMode + } + if($PSBoundParameters.ContainsKey('PaddingMode')){ + $Crypto.Padding = $PaddingMode + } + $Crypto.KeySize = $EncryptionKey.Length*8 + $Crypto.Key = $EncryptionKey + } + Catch + { + Write-Error $_ -ErrorAction Stop + } + } + Process + { + $Files = Get-Item -LiteralPath $FileName + + ForEach($File in $Files) + { + $DestinationFile = $File.FullName + $Suffix + + Try + { + $FileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open) + $FileStreamWriter = New-Object System.IO.FileStream($DestinationFile, [System.IO.FileMode]::Create) + + #Write IV (initialization-vector) length & IV to encrypted file + $Crypto.GenerateIV() + $FileStreamWriter.Write([System.BitConverter]::GetBytes($Crypto.IV.Length), 0, 4) + $FileStreamWriter.Write($Crypto.IV, 0, $Crypto.IV.Length) + + #Perform encryption + $Transform = $Crypto.CreateEncryptor() + $CryptoStream = New-Object System.Security.Cryptography.CryptoStream($FileStreamWriter, $Transform, [System.Security.Cryptography.CryptoStreamMode]::Write) + $FileStreamReader.CopyTo($CryptoStream) + + #Close open files + $CryptoStream.FlushFinalBlock() + $CryptoStream.Close() + $FileStreamReader.Close() + $FileStreamWriter.Close() + + #Delete unencrypted file + if($RemoveSource){Remove-Item -LiteralPath $File.FullName} + + #Output ecrypted file + $result = Get-Item $DestinationFile + $result | Add-Member –MemberType NoteProperty –Name SourceFile –Value $File.FullName + $result | Add-Member –MemberType NoteProperty –Name Algorithm –Value $Algorithm + $result | Add-Member –MemberType NoteProperty –Name Key –Value $Key + $result | Add-Member –MemberType NoteProperty –Name CipherMode –Value $Crypto.Mode + $result | Add-Member –MemberType NoteProperty –Name PaddingMode –Value $Crypto.Padding + $result + } + Catch + { + Write-Error $_ + If($FileStreamWriter) + { + #Remove failed file + $FileStreamWriter.Close() + Remove-Item -LiteralPath $DestinationFile -Force + } + Continue + } + Finally + { + if($CryptoStream){$CryptoStream.Close()} + if($FileStreamReader){$FileStreamReader.Close()} + if($FileStreamWriter){$FileStreamWriter.Close()} + } + } + } +} + +Function Unprotect-File +{ +<# +.SYNOPSIS +Decrypts a file encrypted with Protect-File. + +.DESCRIPTION +Decrypts a file using a provided cryptography key. + +.PARAMETER FileName +File(s) to be decrypted. + +.PARAMETER Key +Cryptography key as a SecureString be used for decryption. + +.PARAMETER KeyAsPlainText +Cryptography key as a String to be used for decryption. + +.PARAMETER CipherMode +Specifies the block cipher mode that was used for encryption. + +.PARAMETER PaddingMode +Specifies the type of padding that was applied when the message data block was shorter than the full number of bytes needed for a cryptographic operation. + +.PARAMETER Suffix +Suffix of the encrypted file to be removed. + +.PARAMETER RemoveSource +Removes the source (encrypted) file after decrypting. + +.OUTPUTS +System.IO.FileInfo. Unprotect-File will return FileInfo with the SourceFile as an added NoteProperty + +.EXAMPLE +Unprotect-File 'C:\secrets.txt.AES' $key +This example decrypts C:\secrets.txt.AES using the key stored in the variable $key. The decrypted file would remove the default extension of '.AES' and the source (encrypted) file would not be removed. + +.EXAMPLE +Unprotect-File 'C:\secrets.txt.Encrypted' -Algorithm DES -Key $key -Suffix '.Encrypted' -RemoveSource +This example decrypts C:\secrets.txt.Encrypted using DES and the key stored in the variable $key. The decrypted file would remove the extension of '.Encrypted' and the source (encrypted) file would be removed. + +.EXAMPLE +Get-ChildItem 'C:\Files' -Recurse | Unprotect-File -Algorithm AES -Key $key -RemoveSource +This example decrypts all of the files under the C:\Files directory using the key stored in the variable $key. The decrypted files would remove the default extension of '.AES' and the source (encrypted) files would be removed. + +.NOTES +Author: Tyler Siegrist +Date: 9/22/2017 +#> +[CmdletBinding(DefaultParameterSetName='SecureString')] +[OutputType([System.IO.FileInfo[]])] +Param( + [Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] + [Alias('PSPath','LiteralPath')] + [string[]]$FileName, + [Parameter(Mandatory=$false, Position=2, ValueFromPipelineByPropertyName=$true)] + [ValidateSet('AES','DES','RC2','Rijndael','TripleDES')] + [String]$Algorithm = 'AES', + [Parameter(Mandatory=$true, Position=3, ValueFromPipelineByPropertyName=$true, ParameterSetName='SecureString')] + [System.Security.SecureString]$Key, + [Parameter(Mandatory=$true, Position=3, ParameterSetName='PlainText')] + [String]$KeyAsPlainText, + [Parameter(Mandatory=$false, Position=4, ValueFromPipelineByPropertyName=$true)] + [System.Security.Cryptography.CipherMode]$CipherMode = 'CBC', + [Parameter(Mandatory=$false, Position=5, ValueFromPipelineByPropertyName=$true)] + [System.Security.Cryptography.PaddingMode]$PaddingMode = 'PKCS7', + [Parameter(Mandatory=$false, Position=6)] + [String]$Suffix, #Assigning default value in code due to it not processing ".$Algorithm" properly when Algorithm is ValueFromPipelineByPropertyName + [Parameter()] + [Switch]$RemoveSource +) + Process + { + #Configure cryptography + try + { + if($PSCmdlet.ParameterSetName -eq 'PlainText') + { + $Key = $KeyAsPlainText | ConvertTo-SecureString -AsPlainText -Force + } + + #Decrypt cryptography Key from SecureString + $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Key) + $EncryptionKey = [System.Convert]::FromBase64String([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)) + + $Crypto = [System.Security.Cryptography.SymmetricAlgorithm]::Create($Algorithm) + $Crypto.Mode = $CipherMode + $Crypto.Padding = $PaddingMode + $Crypto.KeySize = $EncryptionKey.Length*8 + $Crypto.Key = $EncryptionKey + } + Catch + { + Write-Error $_ -ErrorAction Stop + } + + if(-not $PSBoundParameters.ContainsKey('Suffix')) + { + $Suffix = ".$Algorithm" + } + + #Used to store successfully decrypted file names. + $Files = Get-Item -LiteralPath $FileName + + ForEach($File in $Files) + { + #Verify file ends with supplied suffix + If(-not $File.Name.EndsWith($Suffix)) + { + Write-Error "$($File.FullName) does not have an extension of '$Suffix'." + Continue + } + + $DestinationFile = $File.FullName -replace "$Suffix$" + + Try + { + $FileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open) + $FileStreamWriter = New-Object System.IO.FileStream($DestinationFile, [System.IO.FileMode]::Create) + + #Get IV from file + [Byte[]]$LenIV = New-Object Byte[] 4 + $FileStreamReader.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null + $FileStreamReader.Read($LenIV, 0, 3) | Out-Null + [Int]$LIV = [System.BitConverter]::ToInt32($LenIV, 0) + [Byte[]]$IV = New-Object Byte[] $LIV + $FileStreamReader.Seek(4, [System.IO.SeekOrigin]::Begin) | Out-Null + $FileStreamReader.Read($IV, 0, $LIV) | Out-Null + $Crypto.IV = $IV + + #Peform Decryption + $Transform = $Crypto.CreateDecryptor() + $CryptoStream = New-Object System.Security.Cryptography.CryptoStream($FileStreamWriter, $Transform, [System.Security.Cryptography.CryptoStreamMode]::Write) + $FileStreamReader.CopyTo($CryptoStream) + + #Close open files + $CryptoStream.FlushFinalBlock() + $CryptoStream.Close() + $FileStreamReader.Close() + $FileStreamWriter.Close() + + #Delete encrypted file + if($RemoveSource){Remove-Item $File.FullName} + + #Output decrypted file + Get-Item $DestinationFile | Add-Member –MemberType NoteProperty –Name SourceFile –Value $File.FullName -PassThru + } + Catch + { + Write-Error $_ + If($FileStreamWriter) + { + #Remove failed file + $FileStreamWriter.Close() + Remove-Item -LiteralPath $DestinationFile -Force + } + Continue + } + Finally + { + if($CryptoStream){$CryptoStream.Close()} + if($FileStreamReader){$FileStreamReader.Close()} + if($FileStreamWriter){$FileStreamWriter.Close()} + } + } + } +} + +Export-ModuleMember -Function New-CryptographyKey +Export-ModuleMember -Function Protect-File +Export-ModuleMember -Function Unprotect-File \ No newline at end of file