V právním, finančním a zdravotnickém sektoru je generování velkých objemů PDF dokumentů běžnou praxí. Vytvoření dokumentů je však jen polovina bitvy, jejich zabezpečení je stejně tak kritické. Pokud máte archivační systém, který denně zpracovává stovky gigabajtů PDF souborů, může se použití šifrování AES-256 rychle stát úzkým hrdlem z hlediska výkonu.
V tomto článku prozkoumáme, jak dosáhnout vysokorychlostního šifrování PDF pomocí AES-256 v Delphi, a to tím, že se vyhneme vyčerpání paměti a optimalizujeme kryptografické cykly.
Specifikace šifrování PDF
Zabezpečení PDF se významně vyvinulo. Rané verze používaly 40bitový algoritmus RC4, který je dnes snadno prolomitelný. Současný standard (PDF 1.7 Extension Level 3 a PDF 2.0) vyžaduje šifrování AES-256.
V PDF nešifrujete celý blok souboru. Struktura dokumentu (tabulka XRef a struktura slovníků) zůstává ve formátu prostého textu. Místo toho šifrujete Streamy (nezpracovaná data pro obrázky a obsah stránek) a Řetězce (například text metadat). To vyžaduje, aby analyzátor extrahoval data, aplikoval AES CBC (Cipher Block Chaining) a zapsal je zpět.
Úzké hrdlo: Načítání do paměti
Častou chybou při šifrování masivního PDF (např. 2GB naskenovaného archivu) je načtení celého streamu do `TMemoryStream` před jeho předáním kryptografickému modulu. To vede k výjimkám typu nedostatek paměti (OOM) ve 32bitových procesech a masivním výpadkům stránek (page faulting) v 64bitových procesech.
Šifrování streamů v Delphi
Řešením je použít po částech (chunked) streamovací přístup. Pomocí rozhraní Windows Cryptography API: Next Generation (CNG) nebo knihovny, jako je OpenSSL, můžete číst PDF stream v 64KB blocích, blok zašifrovat a zapsat jej přímo do výstupního diskového streamu.
Zde je koncepční příklad v Delphi, který demonstruje šifrovací smyčku s vyrovnávací pamětí pro stream:
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;
Optimalizace kryptografického backendu
Vývojáři v Delphi mají několik možností pro backend AES:
- Nativní implementace Delphi: Snadné nasazení, ale často pomalejší, protože se spouštějí čistě softwarově.
- Windows CNG (BCrypt): Vysoce optimalizované a může využívat hardwarovou akceleraci (instrukce AES-NI na moderních procesorech Intel/AMD).
- OpenSSL (libcrypto): Průmyslový standard, neuvěřitelně rychlý, ale vyžaduje dodání externích DLL knihoven.
Pro serverové aplikace s vysokou propustností je hardwarově akcelerovaný AES-NI povinností. Při použití Windows CNG v Delphi umožňuje mapování funkce BCryptEncrypt vaší aplikaci přenést náročné operace na vyhrazený kryptografický čip procesoru, čímž se režie šifrování efektivně snižuje téměř na nulu.
Závěr
Při šifrování PDF souborů o velikosti gigabajtů se spoléhejte spíše na rozdělování streamu na části než na ukládání do vyrovnávací paměti jako celku a zajistěte, aby váš kryptografický backend využíval hardwarovou akceleraci AES-NI. Tato kombinace zaručuje, že vaše archivační linka poběží rychlostí vašich NVMe disků, namísto aby byla omezována výkonem procesoru.
Poznámka: Vysokorychlostní šifrování AES-256 s využitím chunked streamingu je nativně podporováno v komponentě HotPDF VCL Component.