Technický článek

Šifrování PDF pomocí AES-256 v Delphi: Nastavení HotPDF a úskalí

Příznak oprávnění v PDF není zámek. Je to žádost, kterou soubor klade tomu, co jej otevírá, a prohlížeč ji může svobodně ignorovat. Právě tento jediný fakt určuje, jak byste měli uvažovat o každé další volbě na této stránce. Skutečná důvěrnost pochází jen z jednoho místa: šifrování AES-256 s klíčem odvozeným z hesla, které čtenář nemá. Všechno ostatní, zaškrtávací políčka „no printing" a „no copying", je politika, kterou konformní software souhlasí dodržovat a nepřátelský software ne. Smíchejte tyto dvě vrstvy dohromady a dodáte něco, co v demu působí bezpečně a v terénu uniká

HotPDF je nativní VCL komponenta pro PDF pro Delphi a C++Builder a zpřístupňuje model ochrany ISO 32000 prostřednictvím malé sady vlastností. Nastavit tyto vlastnosti je snadné. Těžké je vědět, která z nich vám kupuje kryptografickou ochranu a která jen zdvořilé doporučení, a dodržet správné pořadí přiřazení, aby šifrování, o které jste žádali, bylo skutečně tím, co dostanete

Co dvě hesla skutečně slibují

Šifrování PDF definuje dvě přihlašovací údaje s odlišnými úkoly a jejich zaměňování je nejčastější chyba návrhu v kódu chráněného výstupu. Uživatelské heslo (user password) hlídá dešifrování. Bez něj, nebo bez vlastnického hesla (owner password), konformní čtečka nedokáže rekonstruovat klíč souboru a obsah zůstává kryptograficky nečitelný. Vlastnické heslo naproti tomu hlídá nastavení oprávnění: čtečka, která obdrží vlastnické heslo, dostane plný přístup bez ohledu na to, co říkají omezovací příznaky

Bity oprávnění stojí na slabší půdě. Tisk, extrakce obsahu, vyplňování formulářů: každý z nich je příznak, který prohlížeč čte a rozhoduje se jej respektovat (ISO 32000-2 §7.6.4). Šifrování chrání bajty. Příznaky oprávnění pouze instruují konformní software, a to až dodatečně. Kdokoli otevře dokument s uživatelským heslem, už má dešifrovaný obsah v paměti, takže „no copy" a „no print" něco znamenají pro slušně se chovající prohlížeč a nic pro odhodlaného útočníka. Postavte model hrozeb kolem této hranice. Důvěrnost žije v uživatelském hesle. Oprávnění formují to, co nabízejí běžné prohlížeče, a to je vše, co dělají

Diagram HotPDF přihlašovacích údajů šifrovaného PDF: uživatelské heslo odvodí klíč souboru a odemkne dešifrování, vlastnické heslo udělí plný přístup přepisující příznaky oprávnění a výstražný pás připomíná, že bity oprávnění ProtectOptions jsou žádosti respektované jen konformním softwarem
Uživatelské heslo nese důvěrnost, zatímco vlastnické heslo jen zvedá omezení; příznaky oprávnění řídí poslušné čtečky a nikoho nepřátelského nezaváží

Pořadí konfigurace: vše před BeginDoc

HotPDF sestaví slovník šifrování a odvodí klíč souboru ve chvíli, kdy proběhne BeginDoc. Cokoli vlastnosti ochrany obsahují v tomto okamžiku, to dokument dostane, a jejich pozdější změna už nic nezmění. Nejdůležitější vlastností je tady CryptKeyLength, která vybírá schéma z hodnot THPDFKeyType k40, k128, aes128 a aes256. Přiřaďte ji po BeginDoc a nedostanete žádnou výjimku, žádné varování, jen soubor, který si potichu ponechal, s čím začal. Tento druh tiché odchylky je ten nejhorší: projde každým lokálním testem a objeví se o měsíce později jako zjištění při auditu shody na stole zákazníka

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'statement.pdf';
    Pdf.ActivateProtection := True;
    Pdf.CryptKeyLength := aes256;        // musí být nastaveno před BeginDoc
    Pdf.UserPassword := 'open-secret';
    Pdf.OwnerPassword := 'admin-secret';
    Pdf.UseAES256R6 := False;            // R=5: nejširší podpora prohlížečů
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 720, 0, 'Account statement, June 2026');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Hesla jsou v UTF-8 a omezená na 127 bajtů, což je limit ISO 32000-2 pro schémata AES-256. Pokud vám zásady pro hesla dávají delší tajemství, ořízněte je sami, na své straně, kde přesně kontrolujete, kde řez padne. Necháte-li to na náhodě, knihovna a nějaký budoucí prohlížeč se mohou neshodnout na tom, kde se ořízne, což vytvoří soubor, který se otevře u vás a stejné heslo odmítne jinde

Revize 5, nebo revize 6: jeden boolean, dva ekosystémy

UseAES256R6 volí mezi dvěma variantami handshaku AES-256 a tato volba má větší důsledky, než by napovídal její typ boolean. Ponechte ji na False a HotPDF zapíše revizi 5, schéma AES-256, které přišlo jako rozšíření PDF 1.7 a které dokáže otevřít zhruba patnáct let prohlížečů zpětně. Nastavte ji na True a dostanete revizi 6, zpevněné odvození klíče standardizované v ISO 32000-2 pro PDF 2.0, které uzavírá známou slabinu v tom, jak revize 5 ověřuje heslo

Revize 6 je tedy z kryptografického hlediska lepší volba. Je to zároveň ta, která věci láme. Soubor v revizi 6 potřebuje prohlížeč postavený pro PDF 1.7 Extension Level 3 nebo PDF 2.0, a spousta nasazeného softwaru není ani jedno z toho: archivy pro správu záznamů, vestavěné renderery v jiných produktech, interní nástroje, kterých se roky nikdo nedotkl. Ty soubor rovnou odmítnou, a udělají to na počítači zákazníka, nikdy na vašem. Praktickým výchozím nastavením je proto revize 5. Sáhněte po revizi 6 jen tehdy, když bezpečnostní politika jmenuje ISO 32000-2 konkrétní revizí a když jste skutečně ověřili, že si ji každý příjemce umí přečíst. Ať tak či onak, zapište si, kterou jste zvolili a proč, protože příští člověk, kdo se tohoto kódu dotkne, se bude ptát

Starší typy klíčů si zaslouží jednu větu, abyste věděli, že je máte přeskočit. THPDFKeyType stále uvádí k40, k128 a aes128, ale existují kvůli reprodukci historických archivů, ne kvůli ochraně nových. 40bitové RC4 padne pod běžným hardwarem a 128bitová schémata předcházejí revizím AES-256, které bude očekávat jakýkoli současný bezpečnostní audit. U dokumentu, který vytváříte v roce 2026, je skutečnou otázkou jen revize 5 proti revizi 6; pokud u nového návrhu saháte po starších typech, něco se pokazilo výše v řetězci

Příznaky oprávnění bez otevíracího hesla

Požadavek je často opakem utajení. Dokument by měl umět přečíst kdokoli, ale tisk nebo extrakce mají být omezené. Vyjádříte to prázdným uživatelským heslem a neprázdným vlastnickým heslem, čemu PDF říká režim open-password, a operace, které chcete povolit, vyjmenujete v ProtectOptions

Delphi toky vedle sebe ukazující ochranné vlastnosti jako CryptKeyLength aes256 přiřazené před BeginDoc produkující soubor AES-256, zatímco totéž přiřazení po BeginDoc nechá původní schéma nedotčené bez výjimky nebo varování
BeginDoc zmrazí šifrovací slovník, takže správné pořadí dá požadovanou revizi AES-256, zatímco špatné pořadí potichu pošle výchozí schéma
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.UserPassword := '';                      // soubor může otevřít kdokoli
Pdf.OwnerPassword := 'rotate-me-quarterly';  // hlídá sadu oprávnění
Pdf.ProtectOptions := [prPrint, prPrint12bit, prExtractContent];
Pdf.BeginDoc;
// ... obsah stránky ...
Pdf.EndDoc;

Množina THPDFProtectOptions se mapuje na bity oprávnění podle ISO: prPrint a prPrint12bit pro tisk ve vysokém rozlišení, prInformationCopy pro obecné kopírování a extrakci, prExtractContent pro extrakci pro asistivní technologie, plus prModifyStructure, prEditAnnotations, prFillAnnotations a prAssemble. Dva z nich si zaslouží varování. Nechte prExtractContent zapnuté téměř v každém profilu, který vytvoříte. Je to bit, který čtečka obrazovky potřebuje k tomu, aby se dostala k textu, a jeho vypnutí potichu promění rozhodnutí o právech v defekt přístupnosti, na který narazí někdo se zdravotním postižením a vy jej nikdy neuvidíte. Druhá past je prPrint samo o sobě, bez prPrint12bit: několik prohlížečů na to reaguje snížením kvality tisku, a vaši uživatelé to nahlásí jako chybu vykreslování, ačkoli jde ve skutečnosti o nastavení oprávnění

Ověření zabere pět minut a patří do vašeho release checklistu. Otevřete vzorek každého profilu v Acrobatu, otevřete Vlastnosti dokumentu a přečtěte si záložku Zabezpečení, která vypisuje algoritmus („AES 256-bit") a jednotlivě uvádí povolené operace. Pak otevřete stejný soubor v nejstarším prohlížeči, který vaši zákazníci skutečně používají, ne v nejnovějším na vašem počítači. Toto druhé otevření je levná pojistka proti tomu, aby soubor v revizi 6 hladce proplul vývojem a zemřel u zákazníka, který nikdy neaktualizoval

Odebrání ochrany z existujících souborů

Dešifrování běží podle stejného modelu vlastností, ale pozpátku. Načtěte dokument s platným přihlašovacím údajem, vypněte ochranu a výsledek uložte bez ní

var
  Pdf: THotPDF;
  PageCount: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    PageCount := Pdf.LoadFromFile('encrypted.pdf', 'open-secret');
    if PageCount > 0 then
    begin
      Pdf.ActivateProtection := False;   // při uložení zahodí šifrování
      Pdf.SaveLoadedDocument('plain.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Tato cesta naparsuje celý dokument do paměti, což je v pořádku u běžných souborů a plýtvání u obřích. Když vstup dosahuje stovek megabajtů, levnější volbou je DecryptFile: dešifruje během kopírování na úrovni souboru a využívá přímou přepisovací cestu AES-256, která se vyhne sestavování celého stromu objektů, kdykoli to vstup dovolí. Je součástí Direct File API popsaného v doprovodném článku o zpracování velkých PDF z Delphi

Omezení, která souvisejí se šifrováním

Dvě omezení stojí za to znát dřív, než kolem šifrování navrhnete řešení, ne až potom. První je archivní shoda. ISO 19005 zakazuje šifrování v PDF/A, takže jakýkoli workflow, který dokument šifruje a zároveň si nárokuje shodu s PDF/A, je z podstaty rozporný; HotPDF vám nedovolí mít obojí v jednom souboru. Když obojí opravdu potřebujete, odpovědí jsou dva artefakty: šifrovaná kopie pro distribuci a samostatná nešifrovaná kopie pro archiv

Druhé omezení je tvrdší. Šifrování PDF nemá žádnou úschovu klíčů (escrow) ani obnovu. Ztratíte-li uživatelské heslo u souboru v R5 nebo R6, vašimi možnostmi jsou hrubá síla, nebo rezignace. Zacházejte proto s vlastnickým a uživatelským tajemstvím stejně jako s jakýmkoli produkčním přihlašovacím údajem. Generujte je, ukládejte je do trezoru, pravidelně je rotujte. Jediná věc, kterou nikdy neuděláte, je zapsat je natvrdo jako konstanty v jednotce, odkud se rovnou dostanou do verzovacího systému a zůstanou navždy v pracovní kopii každého vývojáře

Poslední reflex, který stojí za vybudování. Změna ochrany souboru, který jste nevytvořili, používá stejný mechanismus jako dešifrování, není to samostatná funkce: načtěte jej s jeho heslem přes LoadFromFile, upravte ProtectOptions nebo hesla na místě a zapište jej zpět pomocí SaveLoadedDocument. Pokud umíte soubor dešifrovat, umíte mu i změnit oprávnění, a kód vypadá téměř identicky jako příklad výše

Vlastnosti ochrany ukázané zde jsou součástí standardního HotPDF Delphi Component pro Delphi a C++Builder; produktová stránka nese úplnou referenci k šifrování, včetně kompletního výčtu oprávnění