Technical Article

AES-256 PDF šifravimas Delphi: HotPDF konfigūravimas ir spąstai

PDF leidimų vėliavėlė nėra užraktas. Tai tėra failo prašymas peržiūros programai, kurią atidarantis asmuo gali lengvai ignoruoti. Šis vienintelis faktas nulemia, kaip turėtumėte vertinti bet kurį kitą pasirinkimą šiame puslapyje. Tikrasis konfidencialumas užtikrinamas tik vienu būdu: AES-256 šifravimu, susietu su slaptažodžiu, kurio skaitytojas neturi. Visi kiti dalykai, pavyzdžiui, žymimieji langeliai „be spausdinimo“ ir „be kopijavimo“, yra tiesiog rekomendacijos, kurias standartus atitinkanti programinė įranga sutinka gerbti, o kenkėjiška įranga – ne. Supainiokite šiuos du sluoksnius ir gausite sprendimą, kuris atrodo saugus demonstracijoje, tačiau realybėje nutekina duomenis.

HotPDF yra vietinis VCL PDF komponentas, skirtas Delphi ir C++Builder aplinkoms, kuris atveria ISO 32000 apsaugos modelį per nedidelį savybių rinkinį. Šias savybes nustatyti lengva. Sunkiausia dalis – žinoti, kuris nustatymas suteikia kriptografinę apsaugą, o kuris – tik mandagų pasiūlymą, taip pat teisingai nurodyti priskyrimo seką, kad prašomas šifravimas iš tikrųjų būtų pritaikytas.

Ką iš tikrųjų garantuoja du slaptažodžiai

PDF šifravimas apibrėžia du skirtingus identifikavimo duomenis, o jų supainiojimas yra dažniausia projektavimo klaida apsaugoto kodo kūrime. Vartotojo slaptažodis kontroliuoja iššifravimą. Be jo (arba be savininko slaptažodžio) standartus atitinkanti peržiūros programa negali atkurti failo rakto, todėl turinys lieka kriptografiškai neperskaitomas. Savininko slaptažodis kontroliuoja leidimų nustatymus: peržiūros programai, gavusiai savininko slaptažodį, suteikiama visapusiška prieiga, nepaisant jokių apribojimo vėliavėlių.

Leidimų bitai remiasi silpnesniu pagrindu. Spausdinimas, turinio išgavimas, formų pildymas – kiekvienas iš jų yra vėliavėlė, kurią peržiūros programa perskaito ir pasirenka gerbti (ISO 32000-2 §7.6.4). Šifravimas apsaugo baitus. Leidimų vėliavėlės tik nurodo taisyklę standartus atitinkančiai programinei įrangai ir daro tai jau po fakto. Kiekvienas, atidaręs dokumentą su vartotojo slaptažodžiu, jau turi iššifruotą turinį operatyviojoje atmintyje, todėl apribojimai „nekopijuoti“ ir „nespausdinti“ turi reikšmę tvarkingai veikiančiai programai, tačiau nieko nereiškia pasiryžusiam piktavaliui. Kurkite grėsmių modelį atsižvelgdami į tai. Konfidencialumas priklauso nuo vartotojo slaptažodžio. Leidimai tiesiog nurodo, ką siūlo populiariausios peržiūros programos, ir tai yra viskas, ką jie daro.

Konfigūravimo seka: viskas prieš BeginDoc

HotPDF sukuria šifravimo žodyną ir išveda failo raktą tuo momentu, kai paleidžiamas BeginDoc. Kokios savybės nustatytos tuo metu, tokią apsaugą dokumentas ir gauna, o vėlesni jų pakeitimai nieko nekeičia. Svarbiausia savybė čia yra CryptKeyLength, kuri parenka šifravimo schemą iš THPDFKeyType reikšmių: k40, k128, aes128 ir aes256. Priskyrę ją po BeginDoc iškvietimo, negausite jokios išimties ar įspėjimo – tiesiog failas tyliai išlaikys pradinius nustatymus. Toks tylus nukrypimas yra pats pavojingiausias: jis praeina visus vietinius testus, o po kelių mėnesių išaiškėja kaip reikalavimų neatitikimas kliento sistemoje.

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'statement.pdf';
    Pdf.ActivateProtection := True;
    Pdf.CryptKeyLength := aes256;        // must be set before BeginDoc
    Pdf.UserPassword := 'open-secret';
    Pdf.OwnerPassword := 'admin-secret';
    Pdf.UseAES256R6 := False;            // R=5: widest viewer support
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 720, 0, 'Account statement, June 2026');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Slaptažodžiai yra koduojami UTF-8 formatu ir ribojami iki 127 baitų – tai yra ISO 32000-2 nustatyta riba AES-256 schemoms. Jei jūsų slaptažodžių politika reikalauja ilgesnių paslapčių, apkarpykite jas patys iš anksto, kad tiksliai kontroliuotumėte šį procesą. Palikus tai atsitiktinumui, biblioteka ir būsima peržiūros programa gali nesutarti dėl nukirpimo taško, todėl failas atsidarys pas jus, tačiau atmes tą patį slaptažodį kitoje sistemoje.

5-oji arba 6-oji versija: viena loginė reikšmė, dvi ekosistemos

UseAES256R6 parenka vieną iš dviejų AES-256 algoritmų versijų, ir šis pasirinkimas turi didesnę įtaką, nei leidžia manyti loginis tipas. Palikite reikšmę False ir HotPDF įrašys 5-ąją versiją (revision 5) – AES-256 schemą, kuri atsirado kaip PDF 1.7 išplėtimas ir kurią gali atidaryti maždaug penkiolika metų naudojamos peržiūros programos. Nustatykite True ir gausite 6-ąją versiją (revision 6) – sustiprintą rakto išvedimo schemą, standartizuotą ISO 32000-2 specifikacijoje, skirtoje PDF 2.0, kuri pašalina žinomą 5-osios versijos slaptažodžio tikrinimo silpnybę.

Kriptografiniu požiūriu 6-oji versija yra saugesnė. Tačiau ji gali sukelti suderinamumo problemų. 6-osios versijos failui reikalinga peržiūros programa, pritaikyta PDF 1.7 Extension Level 3 arba PDF 2.0 standartams, o didelė dalis naudojamos programinės įrangos neatitinka šių reikalavimų: dokumentų valdymo archyvai, įterptieji atvaizdavimo įrankiai kituose produktuose ar senos verslo programos. Šios sistemos visiškai atmes failą, ir tai nutiks kliento mašinoje, o ne jūsų. Todėl praktiškai rekomenduojama naudoti 5-ąją versiją. 6-ąją versiją rinkitės tik tada, kai saugumo politika aiškiai reikalauja ISO 32000-2 standarto ir kai esate visiškai įsitikinę, kad visi gavėjai galės jį perskaityti. Bet kuriuo atveju dokumentuokite šį pasirinkimą, nes kitam programuotojui tikrai kils klausimų.

Senesnius raktų tipus pakanka paminėti vienu sakiniu, kad žinotumėte, jog jų naudoti nereikia. THPDFKeyType vis dar pateikia k40, k128 ir aes128 parinktis, tačiau jos skirtos tik istorinių archyvų suderinamumui, o ne naujų failų apsaugai. 40 bitų RC4 algoritmas yra lengvai įveikiamas šiuolaikine aparatine įranga, o 128 bitų schemos yra pasenusios ir neatitinka šiuolaikinių saugumo reikalavimų. Kurdami dokumentą 2026 metais, rinkitės tik tarp 5-osios ir 6-osios versijų. Jei naujame projekte tenka naudoti pasenusius tipus, vadinasi, sistemoje yra architektūrinių problemų.

Leidimų vėliavėlės be atidarymo slaptažodžio

Dažnai reikalavimas yra priešingas slaptumui. Visi turėtų turėti galimybę skaityti dokumentą, tačiau spausdinimas ar turinio kopijavimas turi būti apribotas. Tai pasiekiama naudojant tuščią vartotojo slaptažodį ir užpildytą savininko slaptažodį – PDF formatu tai vadinama atviro slaptažodžio režimu, o leidžiamos operacijos nurodomos ProtectOptions savybėje.

Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.UserPassword := '';                      // anyone can open the file
Pdf.OwnerPassword := 'rotate-me-quarterly';  // guards the permission set
Pdf.ProtectOptions := [prPrint, prPrint12bit, prExtractContent];
Pdf.BeginDoc;
// ... page content ...
Pdf.EndDoc;

THPDFProtectOptions rinkinys atitinka ISO leidimų bitus: prPrint ir prPrint12bit aukštos raiškos spausdinimui, prInformationCopy bendram kopijavimui ir turinio išgavimui, prExtractContent turinio nuskaitymui pagalbinėms technologijoms, taip pat prModifyStructure, prEditAnnotations, prFillAnnotations ir prAssemble. Du iš jų reikalauja įspėjimo. Palikite prExtractContent įjungtą beveik visuose profiliuose – šio bito reikia ekrano skaitytuvams, o jo išjungimas paverčia teisių ribojimą prieinamumo defektu, su kuriuo susidurs neįgalieji. Kitas pavojus yra naudoti tik prPrint be prPrint12bit – kai kurios peržiūros programos į tai reaguoja pablogindamos spausdinimo kokybę, o vartotojai tai įvertins kaip atvaizdavimo klaidą, o ne kaip leidimų nustatymą.

Patikrinimas trunka penkias minutes ir turėtų būti įtrauktas į jūsų projekto užbaigimo kontrolinį sąrašą. Atidarykite kiekvieno profilio pavyzdį su „Acrobat“, atverkite dokumento savybes („Document Properties“) ir peržiūrėkite saugumo skirtuką („Security“), kuriame nurodomas algoritmas („AES 256-bit“) bei leidžiamos operacijos. Tada atidarykite tą patį failą seniausioje peržiūros programoje, kurią naudoja jūsų klientai. Šis antrasis patikrinimas yra pigus draudimas nuo suderinamumo problemų su 6-ąja versija senesnėse sistemose.

Apsaugos pašalinimas iš esamų failų

Iššifravimas atliekamas atvirkštine tvarka. Įkelkite dokumentą su galiojančiu slaptažodžiu, išjunkite apsaugą ir išsaugokite rezultatą be jos.

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;   // drop encryption on save
      Pdf.SaveLoadedDocument('plain.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Šis būdas įkelia visą dokumentą į atmintį, o tai tinka įprastiems failams, tačiau yra neefektyvu dirbant su dideliais dokumentais. Kai failo dydis viršija kelis šimtus megabaitų, geresnis pasirinkimas yra DecryptFile – jis iššifruoja kopijuojant failų lygmeniu ir naudoja tiesioginį AES-256 perrašymo kelią, kuriam nereikia kurti viso objektų medžio atmintyje. Tai yra tiesioginio failų API dalis, aptariama susijusiame straipsnyje apie didelių PDF apdorojimą iš Delphi.

Apribojimai, susiję su šifravimu

Du apribojimus verta žinoti dar prieš pradedant programuoti šifravimą. Pirmasis – suderinamumas su archyvavimo standartais. ISO 19005 draudžia šifravimą PDF/A formatu, zodėl bet koks procesas, kuriame dokumentas yra šifruojamas ir tuo pat metu pretenduoja į PDF/A suderinamumą, yra prieštaringas. HotPDF neleis sukurti tokio failo. Jei jums tikrai reikia abiejų parinkčių, kurkite du failus: šifruotą kopiją platinimui ir atskirą nešifruotą kopiją archyvui.

Antrasis apribojimas yra dar griežtesnis. PDF šifravimas neturi jokių atsarginių raktų ar atkūrimo galimybių. Praradus R5 arba R6 failo vartotojo slaptažodžio, jūsų pasirinkimas bus tik grubi jėga (brute force) arba tiesiog susitaikymas su praradimu. Todėl su savininko ir vartotojo slaptažodžiais elkitės taip pat, kaip su bet kokiais gamybiniais prisijungimo duomenimis: generuokite juos, saugokite saugykloje ir periodiškai keiskite. Vienintelis dalykas, kurio niekada negalima daryti – įrašyti juos kaip konstantas tiesiai kode, iš kur jie pateks į versijų kontrolės sistemą ir bus prieinami visiems programuotojams.

Dar vienas naudingas įprotis: apsaugos keitimas failui, kurio nesukūrėte patys, atliekamas naudojant tą patį mechanizmą kaip ir iššifravimas – įkelkite jį su slaptažodžiu per LoadFromFile, pakeiskite ProtectOptions arba slaptažodžius ir įrašykite atgal naudodami SaveLoadedDocument. Jei galite iššifruoti failą, galite pakeisti ir jo leidimus, o kodas atrodys beveik identiškai aukščiau pateiktam pavyzdžiui.

Čia parodytos apsaugos savybės yra standartinės HotPDF Component, skirto Delphi ir C++Builder, dalis; produkto puslapyje rasite pilną šifravimo dokumentaciją, įskaitant visą leidimų sąrašą.