Műszaki cikk

AES-256 PDF-titkosítás Delphi-ben: HotPDF beállítás és csapdák

A PDF jogosultsági jelzője nem zár. Kérés, amelyet a fájl intéz ahhoz, ami megnyitja, és a megjelenítő nyugodtan figyelmen kívül hagyhatja. Ez az egyetlen tény dönti el, hogyan érdemes gondolkodni az ezen az oldalon szereplő összes többi választásról. Valódi bizalmasság egyetlen helyről jön: olyan jelszóval kulcsolt AES-256 titkosításból, amellyel az olvasó nem rendelkezik. Minden más – a „nem nyomtatható” és a „nem másolható” jelölőnégyzet – olyan szabály, amelynek betartására a szabálykövető szoftver hajlandó, az ellenséges pedig nem. Keverje össze ezt a két réteget, és olyasmit szállít ki, ami bemutatón biztonságosnak érződik, éles környezetben viszont szivárog

A HotPDF natív VCL PDF-komponens Delphihez és C++Builderhez, és az ISO 32000 védelmi modelljét néhány tulajdonságon keresztül teszi elérhetővé. A tulajdonságokat könnyű beállítani. A nehéz rész annak tudása, hogy melyik ad kriptográfiai védelmet és melyik csupán udvarias javaslatot, illetve az értékadások helyes sorrendje, hogy a kért titkosítás valóban az legyen, amit megkap

Mit ígér valójában a két jelszó

A PDF-titkosítás két, eltérő feladatú hitelesítő adatot definiál, és ezek összemosása a védett kimenetet előállító kód leggyakoribb tervezési hibája. A felhasználói jelszó a visszafejtést őrzi. Nélküle – vagy a tulajdonosi jelszó nélkül – a szabálykövető olvasó nem tudja előállítani a fájlkulcsot, és a tartalom kriptográfiailag olvashatatlan marad. A tulajdonosi jelszó ezzel szemben a jogosultsági beállításokat őrzi: az az olvasó, amely a tulajdonosi jelszót kapja, teljes hozzáférést nyer, bármit mondjanak is a korlátozó jelzők

A jogosultsági bitek gyengébb talajon állnak. Nyomtatás, tartalomkinyerés, űrlapkitöltés: mindegyik olyan jelző, amelyet a megjelenítő elolvas, és eldönti, hogy tiszteletben tartja-e (ISO 32000-2 §7.6.4). A titkosítás a bájtokat védi. A jogosultsági jelzők csak utasítják a szabálykövető szoftvert, méghozzá utólag. Aki a felhasználói jelszóval megnyitja a dokumentumot, annak a visszafejtett tartalom már a memóriájában van, tehát a „nem másolható” és a „nem nyomtatható” jelent valamit egy jól nevelt megjelenítőnek, és semmit egy elszántnak. A fenyegetésmodellt e vonal köré építse. A bizalmasság a felhasználói jelszóban lakik. A jogosultságok azt alakítják, mit kínál fel a többségi megjelenítő, és ennyi az egész, amit tesznek

HotPDF diagram titkosított PDF hitelesítő adatokról: a felhasználói jelszó származtatja a fájlkulcsot, és feloldja a dekódolást, a tulajdonosi jelszó teljes hozzáférést ad a jogosultságjelzők felülírásával, egy figyelmeztető sáv pedig megjegyzi, hogy a ProtectOptions jogosultságbitek kérések, amelyeket csak szabálykövető szoftver tisztel
A felhasználói jelszó a bizalmasságot hordozza, míg a tulajdonosi jelszó csupán a korlátozásokat oldja fel; az engedélyjelzők a megfelelés-orientált olvasókat irányítják, és senkit sem köteleznek a rosszhiszeműek közül

Konfigurációs sorrend: minden a BeginDoc előtt

A HotPDF abban a pillanatban építi fel a titkosítási szótárat és származtatja a fájlkulcsot, amikor a BeginDoc lefut. Amit a védelmi tulajdonságok abban a pillanatban tartalmaznak, azt kapja a dokumentum, és utólagos módosításuk semmit nem változtat. A legfontosabb tulajdonság itt a CryptKeyLength, amely a THPDFKeyType értékei – k40, k128, aes128 és aes256 – közül választja ki a sémát. Ha a BeginDoc után adja meg, nem kap kivételt, nem kap figyelmeztetést, csak egy fájlt, amely csendben megtartotta azt, amivel indult. Ez a fajta néma eltérés a legrosszabb: átmegy minden helyi teszten, és hónapokkal később bukkan fel megfelelőségi észrevételként az ügyfél asztalán

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'statement.pdf';
    Pdf.ActivateProtection := True;
    Pdf.CryptKeyLength := aes256;        // a BeginDoc előtt kell beállítani
    Pdf.UserPassword := 'open-secret';
    Pdf.OwnerPassword := 'admin-secret';
    Pdf.UseAES256R6 := False;            // R=5: a legszélesebb megjelenítő-támogatás
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 720, 0, 'Account statement, June 2026');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

A jelszavak UTF-8 kódolásúak, és 127 bájtban vannak korlátozva, ami az AES-256 sémák ISO 32000-2 szerinti határa. Ha a jelszószabályzata ennél hosszabb titkokat ad a kezébe, a csonkítást maga végezze el, a saját oldalán, ahol pontosan Ön szabja meg, hova esik a vágás. Bízza a véletlenre, és a könyvtár meg valamelyik jövőbeli megjelenítő eltérhet a levágás helyében, amiből olyan fájl lesz, amely Önnél megnyílik, máshol viszont visszautasítja ugyanazt a jelszót

5-ös vagy 6-os revízió: egy logikai érték, két ökoszisztéma

A UseAES256R6 a két AES-256 kézfogás között választ, és a döntés súlyosabb, mint amit a logikai típusa sejtet. Hagyja False értéken, és a HotPDF az 5-ös revíziót írja, azt az AES-256 sémát, amely a PDF 1.7 kiterjesztéseként érkezett, és amelyet nagyjából tizenöt évnyi megjelenítő meg tud nyitni. Állítsa True értékre, és a 6-os revíziót kapja: azt a megerősített kulcsszármaztatást, amelyet az ISO 32000-2 szabványosított a PDF 2.0 számára, és amely lezárja az 5-ös revízió jelszó-ellenőrzésének egy ismert gyengeségét

A 6-os revízió tehát kriptográfiailag a jobb történet. Egyben az is, amelyik eltör dolgokat. A 6-os revíziós fájlhoz PDF 1.7 Extension Level 3 vagy PDF 2.0 szintre épült megjelenítő kell, és rengeteg üzembe helyezett szoftver egyik sem: iratkezelő archívumok, más termékekbe ágyazott rajzolók, évek óta nem bolygatott szakrendszeri eszközök. Ezek kereken visszautasítják a fájlt, méghozzá az ügyfél gépén, soha nem az Önén. A gyakorlati alapértelmezés ezért az 5-ös revízió. A 6-oshoz csak akkor nyúljon, ha egy biztonsági szabályzat revízió szerint nevezi meg az ISO 32000-2 szabványt, és ha ténylegesen meggyőződött róla, hogy minden fogadó fél el tudja olvasni. Bármelyiket választja, írja le, melyiket és miért, mert a következő ember, aki hozzáér ehhez a kódhoz, tűnődni fog rajta

A régebbi kulcstípusok megérnek egy mondatot, hogy tudja, miért kell átugrani őket. A THPDFKeyType továbbra is felsorolja a k40, k128 és aes128 értékeket, de ezek történelmi archívumok reprodukálására léteznek, nem új dokumentumok védelmére. A 40 bites RC4 hétköznapi hardveren elhasal, a 128 bites sémák pedig megelőzik azokat az AES-256 revíziókat, amelyeket bármely mai biztonsági felülvizsgálat elvár. Egy 2026-ban készülő dokumentumnál az igazi kérdés csak az 5-ös és a 6-os revízió közti választás; ha egy új tervben mégis a régi típusok után nyúl, valami feljebb elromlott

Jogosultsági jelzők nyitójelszó nélkül

A követelmény gyakran a titoktartás ellenkezője. Bárki elolvashatja a dokumentumot, de a nyomtatást vagy a kinyerést korlátozni kell. Ezt üres felhasználói jelszóval és nem üres tulajdonosi jelszóval fejezi ki – ezt hívja a PDF nyitójelszavas módnak –, az engedélyezni kívánt műveleteket pedig a ProtectOptions tulajdonságban sorolja fel

Egymás melletti Delphi folyamatok: a CryptKeyLength aes256-hez hasonló védelmi tulajdonságok BeginDoc előtt rendelve AES-256 fájlt adnak, míg ugyanez a hozzárendelés BeginDoc után érintetlenül hagyja az eredeti sémát kivétel vagy figyelmeztetés nélkül
A BeginDoc befagyasztja a titkosítási szótárat, így a helyes sorrendű pálya a kért AES-256 revíziót adja, míg a rossz sorrendű pálya csendben az alapértelmezett sémát szállítja
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.UserPassword := '';                      // a fájlt bárki megnyithatja
Pdf.OwnerPassword := 'rotate-me-quarterly';  // a jogosultsági halmazt őrzi
Pdf.ProtectOptions := [prPrint, prPrint12bit, prExtractContent];
Pdf.BeginDoc;
// ... oldaltartalom ...
Pdf.EndDoc;

A THPDFProtectOptions halmaz az ISO jogosultsági bitjeire képződik le: a prPrint és a prPrint12bit a nagy felbontású nyomtatásra, a prInformationCopy az általános másolásra és kinyerésre, a prExtractContent a segítő technológiák általi kinyerésre, ezenfelül ott van a prModifyStructure, a prEditAnnotations, a prFillAnnotations és a prAssemble. Kettő közülük figyelmeztetést érdemel. A prExtractContent jelzőt szinte minden profilban hagyja bekapcsolva. Ez az a bit, amelyre a képernyőolvasónak szüksége van, hogy elérje a szöveget, és a törlése csendben jogosultsági döntésből akadálymentességi hibát csinál, amelybe egy fogyatékossággal élő ember ütközik bele, Ön pedig soha nem látja. A másik csapda a prPrint önmagában, prPrint12bit nélkül: több megjelenítő úgy reagál, hogy rontja a nyomtatási minőséget, a felhasználói pedig ezt rajzolási hibaként fogják bejelenteni, nem pedig annak, ami valójában: jogosultsági beállításnak

Az ellenőrzés öt percbe telik, és a kiadási ellenőrzőlistára tartozik. Nyisson meg mindegyik profilból egy mintát az Acrobatban, hívja elő a dokumentum tulajdonságait, és olvassa el a Biztonság lapot, amely kiírja az algoritmust („AES 256-bit”), és egyesével felsorolja az engedélyezett műveleteket. Utána nyissa meg ugyanazt a fájlt a legrégebbi megjelenítőben, amelyet az ügyfelei ténylegesen futtatnak, nem a legújabban, amely az Ön gépén van. Ez a második megnyitás az olcsó biztosíték arra, hogy egy 6-os revíziós fájl ne siklasson át a fejlesztésen, majd haljon meg egy olyan ügyfélnél, aki soha nem frissített

A védelem eltávolítása meglévő fájlokból

A visszafejtés ugyanazt a tulajdonságmodellt futtatja visszafelé. Töltse be a dokumentumot érvényes hitelesítő adattal, kapcsolja ki a védelmet, és mentse el az eredményt nélküle

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;   // mentéskor elhagyjuk a titkosítást
      Pdf.SaveLoadedDocument('plain.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Ez az útvonal a teljes dokumentumot memóriába elemzi, ami átlagos fájloknál rendben van, óriásiaknál viszont pazarlás. Amikor a bemenet több száz megabájtra rúg, a DecryptFile az olcsóbb lehetőség: fájlszintű másolás közben fejt vissza, közvetlen AES-256 újraírási úton, amely – ha a bemenet engedi – kihagyja a teljes objektumfa felépítését. Ez a Direct File API része, amelyet a nagy PDF-ek Delphiből történő feldolgozásáról szóló társcikk tárgyal

A titkosítással kölcsönható korlátok

Két korlátot érdemes ismerni, mielőtt a titkosítás köré tervez, nem pedig utána. Az első az archiválási megfelelőség. Az ISO 19005 tiltja a titkosítást a PDF/A formátumban, tehát minden olyan munkamenet, amely titkosít egy dokumentumot, és egyszersmind PDF/A-megfelelőséget is állít, felépítésénél fogva önellentmondó; a HotPDF nem engedi, hogy mindkettő egy fájlban legyen. Ha valóban mindkettőre szüksége van, a válasz két külön termék: egy titkosított példány a terjesztéshez és egy külön, titkosítatlan példány az archívumba

A második korlát még nyersebb. A PDF-titkosításban nincs letét és nincs helyreállítás. Veszítse el a felhasználói jelszót egy R5 vagy R6 fájlon, és a lehetőségei a nyers erő vagy a feladás. Kezelje tehát a tulajdonosi és a felhasználói titkokat úgy, ahogy bármely éles hitelesítő adatot. Generálja őket, tárolja páncélszekrényben, cserélje őket ütemezetten. Az egyetlen dolog, amit soha nem szabad megtenni, hogy konstansként beégeti őket egy unitba, ahonnan egyenesen a verziókövetésbe utaznak, és örökre ott ülnek minden fejlesztő munkapéldányában

Egy utolsó reflexet érdemes kiépíteni. Egy nem Ön által készített fájl védelmének módosítása ugyanaz a gépezet, mint a visszafejtés, nem külön funkció: töltse be a jelszavával a LoadFromFile hívással, szerkessze helyben a ProtectOptions beállítást vagy a jelszavakat, és írja vissza a SaveLoadedDocument hívással. Ha vissza tud fejteni egy fájlt, akkor újra tudja engedélyezni is, és a kód majdnem ugyanúgy néz ki, mint a fenti példa

Az itt bemutatott védelmi tulajdonságok a Delphihez és C++Builderhez készült szabványos HotPDF Delphi Component részei; a termékoldal hordozza a teljes titkosítási referenciát, beleértve a jogosultságok teljes felsorolását