W sektorze prawniczym, finansowym i opieki zdrowotnej generowanie dużych ilości dokumentów PDF jest standardową praktyką. Jednakże samo utworzenie dokumentów to tylko połowa sukcesu; równie kluczowe jest ich zabezpieczenie. Jeśli dysponujesz archiwum przetwarzającym setki gigabajtów plików PDF dziennie, zastosowanie szyfrowania AES-256 może szybko stać się wąskim gardłem wydajności.
W tym artykule zbadamy, jak osiągnąć wysoką szybkość szyfrowania plików PDF kluczem AES-256 w środowisku Delphi, omijając wyczerpywanie pamięci i optymalizując pętle kryptograficzne.
Specyfikacja szyfrowania plików PDF
Bezpieczeństwo plików PDF znacznie ewoluowało. Wczesne wersje używały 40-bitowego szyfrowania RC4, które dziś można łatwo złamać. Obecny standard (PDF 1.7 Extension Level 3 oraz PDF 2.0) wymaga szyfrowania AES-256.
W formacie PDF nie szyfruje się całego bloku pliku. Struktura dokumentu (tabela XRef oraz struktura słowników) pozostaje w postaci jawnej. Zamiast tego szyfrujesz strumienie (Streams - surowe dane dla obrazów i zawartości strony) oraz ciągi znaków (Strings - np. tekst metadanych). Wymaga to, aby parser wyodrębnił dane, zastosował algorytm AES CBC (Cipher Block Chaining) i zapisał je z powrotem.
Wąskie gardło: ładowanie do pamięci
Częstym błędem popełnianym podczas szyfrowania ogromnego pliku PDF (np. 2-gigabajtowego zeskanowanego archiwum) jest wczytywanie całego strumienia do obiektu TMemoryStream przed przekazaniem go do silnika kryptograficznego. Prowadzi to do wyjątków braku pamięci (Out-Of-Memory, OOM) w procesach 32-bitowych i ogromnego stronnicowania pamięci (page faulting) w procesach 64-bitowych.
Strumieniowe szyfrowanie w środowisku Delphi
Rozwiązaniem jest zastosowanie podejścia opartym na podziale na porcje (chunked streaming). Korzystając z interfejsu Windows Cryptography API: Next Generation (CNG) lub biblioteki typu OpenSSL, możesz odczytać strumień PDF w 64-kilobajtowych blokach, zaszyfrować blok i zapisać go bezpośrednio w wyjściowym strumieniu dyskowym.
Oto koncepcyjny przykład w języku Delphi, demonstrujący buforowaną pętlę szyfrowania dla strumienia:
uses
System.Classes, System.SysUtils;
const
BUFFER_SIZE = 65536; // 64KB chunks
// This represents your AES-256 encryption routine
procedure EncryptStreamChunk(const InBuffer; var OutBuffer; BytesRead: Integer; const Key: TBytes; const IV: TBytes);
begin
// Call to Windows CNG (BCryptEncrypt) or OpenSSL (EVP_EncryptUpdate)
// ...
end;
procedure EncryptLargePDFStream(InputStream, OutputStream: TStream; const Key, IV: TBytes);
var
InBuffer, OutBuffer: array of Byte;
BytesRead: Integer;
begin
SetLength(InBuffer, BUFFER_SIZE);
// AES CBC requires padding, so the output buffer must be slightly larger
SetLength(OutBuffer, BUFFER_SIZE + 16);
InputStream.Position := 0;
OutputStream.Position := 0;
repeat
BytesRead := InputStream.Read(InBuffer[0], BUFFER_SIZE);
if BytesRead > 0 then
begin
EncryptStreamChunk(InBuffer[0], OutBuffer[0], BytesRead, Key, IV);
// Write the encrypted cipher text directly to disk
OutputStream.Write(OutBuffer[0], BytesRead); // Note: padding logic omitted for brevity
end;
until BytesRead < BUFFER_SIZE;
end;
Optymalizacja silnika kryptograficznego
Programiści Delphi mają do wyboru kilka opcji silnika AES:
- Natywne implementacje Delphi: Łatwe do wdrożenia, ale często wolniejsze, ponieważ działają wyłącznie programowo (w oprogramowaniu).
- Windows CNG (BCrypt): Wysoce zoptymalizowane, mogące korzystać z akceleracji sprzętowej (instrukcje AES-NI w nowoczesnych procesorach Intel/AMD).
- OpenSSL (libcrypto): Standard branżowy, niewiarygodnie szybki, ale wymaga dostarczenia zewnętrznych plików DLL.
W przypadku aplikacji serwerowych o dużej przepustowości sprzętowa akceleracja AES-NI jest obowiązkowa. Przy użyciu Windows CNG w Delphi zmapowanie funkcji BCryptEncrypt pozwala na odciążenie głównego procesu i przekazanie trudnych obliczeń do dedykowanego układu kryptograficznego procesora CPU, co skutecznie redukuje narzut szyfrowania do poziomu bliskiego zeru.
Podsumowanie
Szyfrując pliki PDF liczone w gigabajtach, polegaj na porcjowaniu strumieni zamiast pełnego buforowania pamięci, a także upewnij się, że silnik kryptograficzny wykorzystuje akcelerację sprzętową AES-NI. To połączenie gwarantuje, że procesy Twojego archiwum będą przebiegać z prędkością dysków NVMe, bez obciążania wydajności procesora.
Uwaga: Szybkie szyfrowanie AES-256 wykorzystujące strumieniowanie partiami jest natywnie obsługiwane w komponencie HotPDF VCL Component.