HotPDF Delphi PDF komponenta implementira model kriptografskih filtara ISO 32000-1 §7.6.5 kao tri neovisne politike, a ne jednu zastavicu: ConfigureCryptFilterDefaults zasebno dodjeljuje filtar stringova /StrF, filtar tokova /StmF i filtar ugrađenih datoteka /EFF, SetStreamCryptFilter nadjačava jedan tok, a GetLoadedCryptFilterInfo prijavljuje što ulazna datoteka deklarira. Većina problema interoperabilnosti šifriranih PDF-ova živi u prazninama između te tri politike
Evo kvara koji ljude pošalje u ovaj sloj. Tim isporuči dokument u kojem sadržaj stranice mora ostati čitljiv nizvodnom alatu, ali priloženi sadržaj ne smije, pa postavi /EFF /StdCF i ostavi /StmF /Identity. Acrobat ga otvara bez problema. Sukladan čitač treće strane vrati privitak kao smeće šifriranog teksta, jer je /EFF politika na strani proizvođača o tome koji se filtar primjenjuje na ugrađene datoteke, dok opći čitač i dalje razrješava neoznačeni tok kroz /StmF. Popravak nije druga vrijednost /EFF. Popravak je izričiti filtar /Crypt na samom toku ugrađene datoteke
Čime sloj kriptografskog filtra doista upravlja
Kriptografski filtri sjede između algoritma šifriranja i grafa objekata te odlučuju koje objekte algoritam dodiruje, a ne kako radi. Rječnik /CF unutar rječnika šifriranja preslikava imena u definicije filtara, od kojih svaka nosi metodu /CFM, neobavezni /Length i /AuthEvent. Tri zapisa najviše razine, /StrF, /StmF i /EFF, zatim biraju koji od imenovanih filtara vrijedi za stringove, tokove bez izričitog filtra i ugrađene datoteke. HotPDF namjerno ograničava ono što njegovi ugrađeni rukovatelji mogu zapisati. ConfigureCryptFilterDefaults prihvaća samo rezervirana imena za aktivni rukovatelj: standardni sigurnosni rukovatelj emitira /StdCF ili /Identity, rukovatelj javnog ključa emitira /DefaultCryptFilter ili /Identity, a sve drugo podiže EArgumentException na mjestu poziva. Filtri koje vanjski proizvođači zapisuju pod drugim imenima i dalje se čuvaju na putovima učitavanja, pregleda i ponovnog zapisa radi kompatibilnosti, pa je HotPDF konzervativan kao pisač, a popustljiv kao čitač. Primjenjuju se još dvije zaštite: poziv podiže EInvalidOpException kada serijalizacija dokumenta započne i ponovno ako je dokument u inkrementalnom ažuriranju, jer se politika šifriranja ne može mijenjati između revizija iste datoteke
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.AutoLaunch := False;
Pdf.FileName := 'wrapper.pdf';
Pdf.OwnerPassword := 'owner-secret';
Pdf.UserPassword := 'open-secret';
Pdf.CryptKeyLength := aes128;
// stringovi šifrirani, tokovi stranice otvoreni, privici šifrirani
Pdf.ConfigureCryptFilterDefaults('StdCF', 'Identity', 'StdCF');
Pdf.ActivateProtection := True;
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 12);
Pdf.CurrentPage.TextOut(50, 50, 0, 'Visible stream operators');
Pdf.AddDocumentAttachment('payload.bin', 'Encrypted payload');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Jedno ograničenje vrijedi navesti odmah jer se provjerava kasno i iznenađuje ljude. Imenovani kriptografski filtri u HotPDF-u traže šifriranje dokumenta aes128, aes256 ili aesgcm. Postavite politiku filtra na vrh RC4-a k40 ili k128 i validacijski prolaz koji se pokreće kada je šifriranje uključeno podići će pogrešku, a ne tiho promaknuti vrstu ključa. To je isti stav kao i kod ostatka puta šifriranja PDF-a AES-256 u Delphiju: odbijte dvosmislenu konfiguraciju umjesto da pogađate što je pozivatelj mislio
Zašto unos /Length znači dvije različite stvari?
Zato što ga specifikacija definira u dvjema različitim jedinicama ovisno o sigurnosnom rukovatelju, a HotPDF mora poštovati obje. U rječniku kriptografskog filtra čiji je /CFM jednak /V2, unos /Length izražen je u bajtovima pod standardnim sigurnosnim rukovateljem, a u bitovima pod rukovateljem javnog ključa. /Length u rječniku šifriranja, koji stoji uz /V (ISO 32000-1 §7.6.2), uvijek je u bitovima. Pročitajte rječnik filtra s /Length 16 i imate 128-bitni ključ u datoteci sa standardnim rukovateljem, a odbijenu datoteku pod javnim ključem. HotPDF to normalizira kada uhvati učitanu konfiguraciju. Množi /Length filtra /V2 s osam samo kada datoteka nije šifrirana javnim ključem, vraća se na /Length razine dokumenta kada filtar izostavi vlastiti i rezultat sprema u THPDFCryptFilterInfo.KeyLengthBits. AESV2 je fiksiran na 128 bitova, a AESV3 i AESV4 na 256 jer te metode nemaju pregovaračku veličinu ključa. Strogi dio dolazi zatim: prihvaćaju se samo 40-bitni i 128-bitni /V2. Filtar koji se razriješi u bilo koju drugu duljinu prijavljuje se kao nedostupan i operacija ne uspijeva, umjesto da se zaokruži na 128 uz pretpostavku da je većina proizvođača ionako mislila na 128. Tiha normalizacija duljine ključa način je da isporučite datoteku koja se dešifrira na vašem računalu, a nigdje drugdje
var
Reader: THotPDF;
Info: THPDFCryptFilterInfo;
I: Integer;
begin
Reader := THotPDF.Create(nil);
try
Reader.AutoLaunch := False;
if Reader.LoadFromFile('incoming.pdf', 'open-secret') <> 1 then
Exit;
// /StrF i /StmF zadano su Identity; /EFF zadano je /StmF
WriteLn(Reader.LoadedStringCryptFilterName); // StdCF
WriteLn(Reader.LoadedStreamCryptFilterName); // Identity
WriteLn(Reader.LoadedEmbeddedFileCryptFilterName); // StdCF
for I := 0 to Reader.GetLoadedCryptFilterCount - 1 do
if Reader.GetLoadedCryptFilterInfo(I, Info) then
if (Info.Method = hcfmV2) and
not (Info.KeyLengthBits in [40, 128]) then
raise Exception.CreateFmt(
'crypt filter /%s: unsupported V2 key length %d',
[String(Info.Name), Info.KeyLengthBits]);
finally
Reader.Free;
end;
end;
Što jamči /CFM /None i kako se /Identity razlikuje?
Do istog ishoda dolaze različitim putovima, a njihovo miješanje kvari pretrage. Imenovani filtar čiji je /CFM /None i imenovani filtar kojem /CFM potpuno nedostaje oba znače da taj filtar ne šifrira ni ne dešifrira — HotPDF nedostajući unos prije razrješavanja preslikava na None, pa oba završavaju na hcfmNone sa zabilježenom duljinom ključa nula. /Identity drugačije je vrste: to je rezervirano ime koje potpuno zaobilazi pretragu /CF, pa dokument može referencirati /Identity bez njegove definicije u /CF. Imena PDF-a razlikuju velika i mala slova, zbog čega je još jedan detalj implementacije neupitan: nijedna pretraga kriptografskog filtra ne smije ignorirati veličinu slova. HotPDF razrješava imena podrječnika /CF, unos filtra /Length i provjeru toka /Type kroz rječnike koji razlikuju velika i mala slova. Datoteka koja definira /stdcf dok /StmF pokazuje na /StdCF neispravna je, a tretiranje njih kao istog ključa pretvorilo bi uočljiv autorski propust u tiho pogrešno primijenjen ključ na svaki tok u dokumentu
Kako učvrstiti /EFF na tokovima ugrađenih datoteka
Kada se /EFF razlikuje od /StmF, tok ugrađene datoteke treba izričiti početni unos /Crypt u svojem /Filteru i odgovarajući rječnik /DecodeParms koji na istoj poziciji polja nosi /Name. HotPDF to razrađuje po toku u trenutku spremanja: otkriva /Type /EmbeddedFile, nasljeđuje konfigurirani filtar ugrađene datoteke i emitira izričitu oznaku /Crypt samo kada se naslijeđeno ime razlikuje od efektivne zadane vrijednosti toka. Kada se /EFF i /StmF podudaraju, oznaka se ne zapisuje jer bi čitač ionako razriješio isti filtar. Pozicija u polju tada je jednako važna kao i ime. Kada HotPDF ponovno čita tok, pretražuje /Filter za unos /Crypt, bilježi njegov indeks i zatim u polju /DecodeParms traži isti indeks kako bi pronašao /Name. /Crypt na indeksu 0 uparen s parametrima na indeksu 1 razrješava se u /Identity, a ne u vaš filtar. Zato pisač također popunjava polje parametara nulom kada je tok prije imao /Filter, ali nije imao /DecodeParms: pozicije moraju ostati poravnate
Ispod toga krije se oštrija zamka. Ako je postojeći /Filter ili /DecodeParms neizravni objekt — što je uobičajeno u datotekama iz generatora koji dijele jedno polje filtara među mnogim tokovima — umetanje /Crypt na mjestu izmijenilo bi zajednički graf filtara i pokvarilo svaki drugi tok koji na njega pokazuje. HotPDF razrješava neizravni objekt i najprije ga klonira u izravni objekt privatan za tok, brišući brojeve objekta i generacije, pa izvorni neizravni korijen nikad nije ugrađen u novo polje. Za tok koji je već koristio ASCIIHexDecode serijalizirani rezultat je /Filter [ /Crypt /ASCIIHexDecode ] s /DecodeParms [ << /Type /CryptFilterDecodeParms /Name /StdCF >> ... ]. Ista disciplina pozicija upravlja svakim drugim lancem filtara, uključujući one kroz koje prolazite kada izdvajate slike iz učitanog PDF-a kroz njihove filtre dekodiranja
// Editor već drži učitani dokument, a ContentStream je
// THPDFStreamObject čiji je /Filter neizravan naziv /ASCIIHexDecode
Editor.OwnerPassword := 'owner-secret';
Editor.UserPassword := 'open-secret';
Editor.CryptKeyLength := aes128;
Editor.ConfigureCryptFilterDefaults('StdCF', 'Identity');
Editor.SetStreamCryptFilter(ContentStream, 'StdCF');
Editor.ActivateProtection := True;
Editor.SaveLoadedDocument('out.pdf');
// Prazno ime briše nadjačavanje i pri sljedećem spremanju uklanja zastarjeli /Crypt
// unos zajedno s njegovim parametrima dekodiranja
Editor.SetStreamCryptFilter(ContentStream, '');
Editor.SaveLoadedDocument('cleared.pdf');
Nasljeđuju li tokovi objekata politiku /Encrypt iz dokumenta?
Ne, a pretpostavka da je nasljeđuju pouzdan je način za proizvodnju smeća. Tok objekata mora slijediti stvarnu politiku /StmF ili vlastitu izričitu oznaku /Crypt: sama prisutnost rječnika /Encrypt ne čini svaki spremnik /ObjStm šifriranim tekstom. Dokument s /StmF /Identity ima tokove objekata u otvorenom tekstu iako su njegovi stringovi potpuno šifrirani, a dekoder koji ih ipak dešifrira predaje fazi inflate ulaz koji nikad nije bio izlaz deflatea
Posljedica za članove objekta dio je koji vrijedi pročitati dvaput. Prema ISO 32000-1 §7.5.7, stringovi unutar šifriranog toka objekata već su otvoreni tekst nakon dešifriranja samog spremnika, pa bi njihovo ponovno dešifriranje bilo dvostruko dešifriranje. HotPDF to štiti tako da provjeri je li spremnik svakog objekta tipa 2 bio šifriran i preskoči objekt kada jest, a preskakanja broji u XRefProbeDecryptObjStmSkips kao izravan dokaz da se zaštita aktivirala. Kada je spremnik bio otvoren, stringovi članova nikad nisu bili pokriveni ničim, pa HotPDF materijalizira te članove i primjenjuje /StrF na svaki pojedinačno — ključano, kako implementacija stvarno radi, brojem i generacijom objekta člana, a ne brojem objekta spremnika /ObjStm. Obrnite to na datoteci s miješanom politikom i svaki string u svakom komprimiranom objektu dekodira se u šum. Pravila na razini spremnika obrađena su detaljnije u bilješkama o tokovima PDF objekata i inkrementalnim ažuriranjima
Gdje HotPDF odbija pogađati
Semantika kriptografskih filtara ne postoji ispod /V 4, pa HotPDF odbija svako nadjačavanje po toku u takvoj datoteci s izričitom pogreškom, umjesto da zapiše oznaku /Crypt koju nijedan sukladan čitač ne bi poštovao. Isto vrijedi na strani čitanja: rječnik šifriranja s /V ispod 4 briše sva tri učitana imena filtara jer ondje nema ničega za prijaviti. Još se tri granice namjerno provode:
- Filtar po toku različit od
Identityna dokumentu šifriranom javnim ključem odbija se jer politika specifična za tok pod rukovateljem javnog ključa treba spremnik primatelja specifičan za tok, koji HotPDF još ne emitira - Ugrađene datoteke šifrirane javnim ključem čiji se
/EFFrazlikuje od efektivnog/StmFodbijaju se iz istog razloga, umjesto da se zapisuju u obliku koji nitko ne može dešifrirati - Brzi put izravnog šifriranja datoteke AES-256 primjenjuje se samo kada se stringovi, tokovi i ugrađene datoteke svi razriješe u istu metodu kriptografskog filtra i nijedan objekt u datoteci ne nosi izričiti
/Crypt; miješana politika ili otvoreni metapodaci prisiljavaju povratak na puni put grafa objekata
Nijedna od ovih odluka nije odluka o performansama. One označavaju mjesta na kojima pogrešna pretpostavka daje PDF koji se otvara u jednom pregledniku, zakazuje u drugom i programeru ne daje nikakav signal dok ga korisnik ne prijavi. Odbijanje pri ConfigureCryptFilterDefaults ili pri spremanju košta jednu iznimku; tiho pogrešno ključan privitak košta cijeli ciklus podrške. Ako gradite softver za Delphi ili C++Builder koji proizvodi ili troši šifrirane PDF-ove — selektivno otvoreni sadržaj stranice sa šifriranim privicima, šifrirane omote sadržaja PDF-a 2.0 ili interoperabilnost s datotekama čije kriptografske politike niste vi odabrali — ovdje opisani API kriptografskih filtara isporučuje se u aktualnoj HotPDF Delphi PDF component, zajedno s putovima šifriranja, tokova objekata i inkrementalnih ažuriranja na kojima počiva