Szyfrowanie plików za pomocą Powershell.

Ostatnio straszne zamieszanie wokół tzw. RODO. W związku z powyższym postanowiłem opisać pewną metodę która może pomóc w bezpiecznym – bo szyfrowanym – przechowywaniu plików np. z kopiami baz SQL. Scenariusz jest następujący – robicie kopie zapasowe baz danych lub innych dowolnych plików. Kopie składujesz na jakimś sieciowym NAS lub innym nośniku, ale ponieważ pliki owe zawierają wrażliwe dane (np. bazę kadr, płac, pacjentów itp.) chciałbyś aby sama kopia była zaszyfrowana. Jeśli taką kopie wykonujesz jakimś zadaniem-skryptem itp., z pomocą przyjdzie poniższa nakładka na moduł którego autorem jest Tyler Siegrist. Jego możliwości są dużo większe niż poniższy przykład – polecam lekturę:

https://gallery.technet.microsoft.com/scriptcenter/EncryptDecrypt-files-use-65e7ae5d/view/Discussions

O co chodzi w skrypcie.

Skrypt ładuje moduł Tyler’a i wykorzystuje go do trzech zadań:

  1. Generowania nowego  klucza AES i zapis do pliku jako plaintext.
  2. Szyfrowanie wskazanego pliku ZIP  kluczem zapisanym w pliku,
  3. Odszyfrowanie wskazanego pliku i rozpakowanie jego zawartości do pliku ZIP.

Oczywiście podobną funkcjonalność mają narzędzia typu 7-zip itp. ale ja postanowiłem zrobić swoje – lekkie i wykorzystujące metody zawarte w systemie. Skrypt możemy wykorzystać jako element systemu do backupów i wyzwalać go z innego skryptu. Klucz AES jest zapisany w pliku tekstowym zapisanym gdziekolwiek w systemie (choćby na pendrive). Można na przykład łatwo wpiąć go jako dodatkowy krok np. do skryptu wykonującego kopię bazy danych. W ten sposób ktoś kto „podprowadzi” Ci pliki z NAS, albo po prostu ukradnie Ci NAS, nie będzie miał klucza potrzebnego do odczytu który jest gdzieś na serwerze, lub jest kryty gdziekolwiek w sieci. Oczywiście wszystko trzeba skonfigurować rozważnie i jak najbezpieczniej. Moduł Tylera umożliwia zapisanie klucza również w Windows Credential Manager. To lepsza metoda. Mogę ją opisać później – jeśli jest taka potrzeba. Napisz mi maila.

Działanie:

1) Generowanie nowego klucza AES256:

.\Crypto.ps1 -path c:\temp\key256.aes -option generatekey

spowoduje wygenerowanie nowego klucza który możemy zapisać w dowolnym miejscu i wykorzystywać go później. Tego nie ma co wpinać do zadania backupu.

2) kompresja i szyfrowanie:

.\Crypto.ps1 -path d:\backup\daily\20180511 -filekey C:\temp\key256.aes -outputfolder \\nas\backup\sql\ -option protect

spowoduje zapakowanie do ZIP folderu d:\backup\daily\20180511 i zaszyfrowanie wykorzystaniem klucza key256.aes a następnie umieszczenie go w \\nas\backup\sql\. Plik wynikowy będzie miał taką samą nazwę jak źródłowy folder ale dostanie dodatkowe rozszerzenie AES (pds.zip.AES).

3) Odszyfrowanie i dekompresja

.\Crypto.ps1 -path \\nas\backup\sql\20180511.zip.AES -filekey C:\temp\key256.aes -outputfolder c:\temp\ -option unprotect

Jak nietrudno zgadnąć, skrypt odszyfruje 20180511.zip.AES zapisany na NAS i rozpakuje go do folderu c:\temp.

Skrypt:

param (
    [string]$Path = $(throw "-path parameter is obligatory"),
    [string]$filekey = "",
    [string]$outputfolder = "",
    [string]$option =  $(throw "protect, unprotect, generatekey")
    )


Import-Module .\FileCryptography.psm1 -DisableNameChecking

function New-ZipDirectory ($DirectoryName, $destinationfile)
{ 
    $FileAbsolutePath = Resolve-Path $DirectoryName
     [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') 
    [System.IO.Compression.ZipFile]::CreateFromDirectory($FileAbsolutePath,$destinationfile) 
}
function Extract-ZIP ($Source, $destination)
{  
   
     [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') 
    [System.IO.Compression.ZipFile]::ExtractToDirectory($Source,$destination) 
    
}

If ($Option -eq "generatekey")
{
    New-CryptographyKey -Algorithm AES -KeySize 256 -AsPlainText >> $path
	Write-Host "Key file path: $path"
}

elseif($Option -eq "protect")
{
    
    $filename = Split-Path -Path $Path -Leaf
    $targetfile = Join-Path $outputfolder "$filename.zip"
	If ((Test-Path -path $targetfile) -eq $true)
	{
		Remove-Item -path $targetfile -force
	}
    Write-Host "used key:$filekey"  
    $filekey = Get-Content -Path $filekey -Force
    	
    New-ZipDirectory $path $targetfile
    Protect-File -FileName $targetfile -KeyAsPlainText  $filekey -Algorithm AES
    Remove-Item -Path $targetfile -Confirm:$false -Force
}

elseif ($option -eq "unprotect")
{
    "unprotecting file $path"
    Unprotect-File -FileName $Path -KeyAsPlainText (Get-Content -Path $filekey) -Algorithm AES
    $targetpath = Split-Path -Path $path -Parent
    $targetdir = Join-Path $targetpath ((Split-path $path -Leaf).Trim(".zip.AES"))
    Write-Host "Path is: $path"
    Write-Host "Target is:     $targetdir"
    If ((Test-Path -Path $targetdir) -eq $true){}
    else 
    {
        New-Item -Path $targetdir -ItemType Directory
    }
    
     Write-host "Extract-ZIP -sourcefile $path -destinationDirectory $targetdir"
     $filetoExtract = $path.Trim(".AES")
     Extract-ZIP -Source $filetoExtract -destination $targetdir
     Remove-Item -Path $filetoExtract -Confirm:$false -Force

}

else
{
    Write-Host "Please select correct option: protect, unprotect, generatekey"
}

Write-host "End."

Pamiętajcie, że w tym samym folderze spodziewa się on modułu Tylera który możecie pobrać tu: https://gallery.technet.microsoft.com/scriptcenter/EncryptDecrypt-files-use-65e7ae5d/file/165403/14/FileCryptography.psm1

Smacznego.