Ochrana citlivých údajov vo vnútri dokumentov PDF je primárnou požiadavkou pre systémy správy zdravotníckych (HIPAA) a právnych dokumentov. Moderná špecifikácia PDF podporuje 256-bitové šifrovanie AES. Zatiaľ čo zašifrovanie jednoduchej 5-stranovej zmluvy je triviálne a okamžité, aplikácia šifrovania AES-256 na viacgigabajtový archívny PDF súbor môže zastaviť celú operáciu alebo spôsobiť zlyhania pamäte, ak sa to nevykoná s optimalizovanými prúdmi I/O.
Pochopenie štruktúry šifrovania PDF
V dokumente PDF nešifrujete celý blok súboru. Štruktúra dokumentu (tabuľka XRef a štruktúra slovníkov) zostáva vo forme obyčajného textu. Namiesto toho šifrujete Streamy (surové dáta pre obrázky a obsah stránky) a Reťazce (Strings, napríklad text metaúdajov). To si vyžaduje, aby analyzátor extrahoval dáta, aplikoval AES CBC (Cipher Block Chaining) a zapísal ich späť.
Úzke miesto: Načítavanie do pamäte
Bežnou chybou pri šifrovaní obrovského PDF (napríklad 2 GB skenovaného archívu) je načítanie celého streamu do objektu TMemoryStream pred jeho odovzdaním kryptografickému nástroju. Toto vedie k výnimkám nedostatku pamäte (Out-Of-Memory, OOM) v 32-bitových procesoch a k masívnym výpadkom stránok (page faulting) v 64-bitových procesoch.
Postupné šifrovanie prúdov (Streaming) v Delphi
Riešením je použitie sekvenčného prístupu vo väčších blokoch. Použitím rozhrania Windows Cryptography API: Next Generation (CNG) alebo knižnice ako OpenSSL, môžete prečítať stream PDF v 64 KB blokoch, zašifrovať blok a zapísať ho priamo do výstupného streamu disku.
Tu je koncepčný príklad v Delphi demonštrujúci slučku šifrovania s vyrovnávacou pamäťou pre 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;
Optimalizácia kryptografického backendu
Vývojári v Delphi majú na výber z niekoľkých možností pre backend AES:
- Natívne implementácie v Delphi: Jednoduché na nasadenie, ale často pomalšie, pretože sa vykonávajú čisto softvérovo.
- Windows CNG (BCrypt): Vysoko optimalizované a môžu využívať hardvérové zrýchlenie (inštrukcie AES-NI na moderných procesoroch Intel/AMD).
- OpenSSL (libcrypto): Priemyselný štandard, neuveriteľne rýchly, ale vyžaduje distribúciu externých knižníc DLL.
Pre vysokovýkonné serverové aplikácie je hardvérovo akcelerované AES-NI nevyhnutné. Pri použití Windows CNG v Delphi umožňuje mapovanie funkcie BCryptEncrypt vašej aplikácii presunúť náročné úlohy na vyhradený kryptografický čip procesora, čím sa efektívne zníži zaťaženie šifrovaním na hodnotu blízku nule.
Záver
Pri šifrovaní PDF s veľkosťou v gigabajtoch sa spoliehajte na rozdelenie prúdu dát do blokov namiesto úplného ukladania do pamäte a zabezpečte, aby váš kryptografický backend využíval hardvérovú akceleráciu AES-NI. Táto kombinácia zaručuje, že váš archivačný reťazec bude bežať rýchlosťou vašich diskov NVMe, namiesto toho, aby bol obmedzený procesorom.
Poznámka: Vysokorýchlostné šifrovanie AES-256 využívajúce postupné načítavanie po blokoch je natívne podporované v komponente HotPDF VCL Component.