Kahden gigatavun PDF:n salaus (Encrypting a 2 GB PDF) kuulostaa virtautusongelmalta (streaming problem): avaa tiedosto, puske (push) kaksi gigatavua (two gigabytes) AES-256:n läpi, kirjoita tulos. Tuo (That) mallinnus (mental model) on väärin (wrong) tavalla (way), joka ratkaisee (decides the) koko suorituskykybudjetin (entire performance budget). ISO 32000-1 §7.6 asettaa (sets) PDF-salauksen (encryption) rakeisuuden (granularity) yksittäisen (individual) objektin tasolle — jokainen virta (stream) ja jokainen merkkijono (string) salataan erikseen (separately), kullakin oma alustusvektorinsa (initialization vector) ja (and) oma täytteensä (padding). Kahden gigatavun (2 GB) skannattu arkisto (scanned archive), jossa on 500 000 objektia, tarkoittaa (is) 500 000 pientä CBC-operaatiota, ei yhtä pitkää (long) läpivientiä (pass), ja tuossa mittakaavassa (at that scale) jokaisen operaation ympärillä oleva (around each operation) kiinteä kustannus (fixed cost) merkitsee enemmän (matters more) kuin itse AES-aritmetiikka sen (inside it) sisällä
Tämä (This) artikkeli (article) kertoo (is about) tuosta kiinteästä kustannuksesta: mihin aika (time) kuluu (goes), kun Delphi-koodi soveltaa (applies) AES-256:ta erittäin (very) suuriin (large) asiakirjoihin (documents), ja miten sen saa (to get it) takaisin (back). Asennuspuolen (setup side) osalta — salasanat (passwords), oikeusliput (permission flags), revision 5 vastaan (versus) 6 -yhteensopivuuskutsu (compatibility call) — katso (see) rinnakkainen (companion) teksti AES-256 -salauksen määrittämisestä HotPDF:ssä; mitään siitä (none of it) ei toisteta (repeated) tässä (here)
Puoli miljoonaa (Half a million) CBC-operaatiota, ei yksi läpivienti
Tiedoston luuranko (skeleton) pysyy (stays in) selkokielisenä (plaintext). Ristiviittaustaulukot (Cross-reference tables), objektinumerot (object numbers), sanakirja-avaimet (dictionary keys), sivupuu (page tree): mitään näistä ei (none of it) salata (is encrypted), mikä on tapa (which is how), jolla lukija pystyy (can) paikantamaan objektit (locate objects) ennen kuin se on vahvistanut (validated a) salasanan (password). Se, minkä standardi salaa (encrypts is), on sisältö (content) — virtadata (stream data), kuten sivujen kuvaukset (page descriptions), kuvat, fontit ja liitteet (attachments), sekä (plus) merkkijonot (strings), kuten meta-arvot (metadata values) ja huomautusten (annotation) tekstit. AES-256 kryptosuodattimen (crypt filter) alla (under) jokainen niistä käsitellään (processed on) omillaan (its own): uusi satunnainen (fresh random) 16 tavun (byte) IV, CBC-operaatio tavujen yli (over the bytes), lohkon täyttö (block padding) 16 tavun rajalle (boundary), ja selväkielisenä (in the clear) ennen (ahead of) salakirjoitustekstiä (ciphertext) kirjoitettu (written) IV
Tästä seuraa (follow) kaksi seurausta (consequences). Ensinnäkin (First), salakirjoitusteksti on aina pidempi (longer) kuin selkokieli (plaintext): IV lisää 16 tavua (bytes) ja täyttö (padding) lisää (adds) 1 - 16 tavua lisää (more), joten 100 tavun merkkijono vie (occupies) levyllä 128 tavua ja tyhjä virta (empty stream) tuottaa edelleen (still produces) 32 tavua. Koodi, joka (that) mitoittaa (sizes) tulostepuskurin (output buffer) syötteen pituuden (input length) mukaan, tai kirjoittaa takaisin (writes back) vain yhtä monta (as many) tavua kuin se luki (read), tuottaa tiedostoja (files that), joiden (to) salauksen purku epäonnistuu (fail to decrypt) jokaisen objektin viimeisen lohkon (last block) kohdalla. Toiseksi (Second), kustannus (cost) seuraa objektien määrää (object count), ei vain (not just) tavumäärää (byte count). Skannattu arkisto keskittää (concentrates) tavunsa (its bytes in) muutamiin (few) suuriin (large) kuvavirtoihin (image streams), mutta kantaa satojatuhansia (hundreds of thousands of) lyhyitä (short) virtoja ja pieniä merkkijonoja, joissa laskun muodostaa (is the bill) toimintokohtainen yleiskustannus (overhead), ei AES
Ainoa (The one) armo (mercy in) AES-256:n suunnittelussa (design) on avainten käsittely (key handling). Turvakäsittelijät (Security handlers) versioon (revision) 4 asti (up to) johtivat (derived a) erillisen avaimen (distinct key) jokaista (every) objektia varten (for) tiivistämällä (by hashing the) tiedostoavaimen (file key) yhteen (together with) objektin ja sukupolven (generation) numeroiden kanssa (numbers), pakottaen uuden (forcing a fresh) avainaikataulun (key schedule) joka kerta (each time). /V 5 -järjestelmät (schemes) pudottivat (dropped) objektikohtaisen johtamisen (per-object derivation): yksi (one) satunnainen (random) 256-bittinen (256-bit) tiedostoavain (file key) salaa (encrypts) jokaisen objektin asiakirjassa. Tuo tosiasia (That fact) lisensoi jokaisen alla olevan (below) optimoinnin — kallis (expensive) kryptografinen (cryptographic) tila voidaan rakentaa kerran (once per) tiedostoa kohden (file), ei (not once) kerran (per) objektia kohden (object)
R6 /Encrypt-sanakirja (dictionary): yksi hidas avaus (slow open), halpoja objekteja
Revision (A revision) 6 asiakirja julistaa (declares its) järjestelmänsä (scheme) trailerin /Encrypt-sanakirjassa (dictionary), ja (and the) merkitykselliset (that matter) merkinnät (entries) mahtuvat (fit in) muutamalle riville (few lines):
/Filter /Standard
/V 5 /R 6 /Length 256
/CF << /StdCF << /CFM /AESV3 /Length 32 /AuthEvent /DocOpen >> >>
/StmF /StdCF /StrF /StdCF
/O ...48 tavua... /U ...48 tavua...
/OE ...32 tavua... /UE ...32 tavua...
/Perms ...16 tavua... /P -3904 /EncryptMetadata true
/V 5 valitsee 256-bittisen avainarkkitehtuurin (key architecture) ja /R 6 karkaistun (hardened) ISO 32000-2 -kättelyn (handshake). /CF määrittelee (defines) nimetyn (named) kryptosuodattimen (crypt filter) — /AESV3 tarkoittaa (means) AES-256:ta CBC-tilassa eteen (prepended) liitetyn IV:n kanssa — ja /StmF sekä /StrF liittävät (assign) kyseisen (that) suodattimen (filter to) vastaavasti (respectively) virtoihin (streams) ja merkkijonoihin (strings). /O, /U, /OE ja /UE sisältävät salasanan vahvistus- ja avaimen paketointimateriaalin (key-wrapping material), ja /Perms kantaa AES-salattua (AES-encrypted) kopiota käyttöoikeusbiteistä (permission bits), jotta (so a) vihamielinen (hostile) muokkaaja (editor) ei voi (cannot) hiljaa (silently) kääntää (flip) /P:tä
Kustannusrakenne (The cost structure) piiloutuu (hides in) /OE- ja /UE-kenttiin. Tiedostoavaimen purkaminen (Unwrapping the file key from) niistä (them) ajaa Algoritmin (Algorithm) 2.B, joka on toistettu (iterated) avaimenjohtamistoiminto (key-derivation function), joka (chaining) ketjuttaa SHA-256-, SHA-384- ja SHA-512-kierroksia — ainakin 64 niistä (of them), riippuvaisella (data-dependent) pysähtymissäännöllä (stopping rule) — ja se on rakennettu (built) tarkoituksella hitaaksi (deliberately slow), jotta (so that) salasanojen (password) arvaaminen (guessing) pysyy kalliina (stays expensive). Tuo (That) hinta (price) maksetaan kerran, kun kirjoittaja (writer) tuottaa (produces) tiedoston, ja kerran, kun lukija (reader) avaa sen, kumpikin vie muutaman (single-digit) millisekunnin (milliseconds each). Puolen miljoonan objektin (half-million-object) tiedostossa KDF on pelkkää kohinaa (is noise), ja jos (and if a) tallennus (save) on hidas (slow), Algoritmi 2.B ei ole epäilty (is not the suspect); se on (is) objektikohtainen silmukka (per-object loop)
Uudelleenkäytä avainkahva (key handle), uudelleenkäytä raapustuspuskuri (scratch buffer)
Naiivi (The naive) toteutus on siisti (tidy) apufunktio (utility function): EncryptAes256Cbc-apuri (helper that), joka avaa Windowsin (Windows) CNG-tarjoajan (provider), valitsee (selects) CBC:n, luo (generates) avainobjektin (key object), salaa (encrypts) yhden puskurin ja purkaa (tears) kaiken alas (down). Oikein (Correct), yksikkötestattava (unit-testable) ja katastrofaalinen (disastrous) 500 000 iteraation (iteration) silmukan (loop) sisällä. Microsoftin (Microsoft's) dokumentaatio merkitsee (flags) BCryptOpenAlgorithmProvider-kutsun kalliiksi (expensive) ja suosittelee kahvan välimuistiin tallentamista (caching the handle), ja BCryptGenerateSymmetricKey ajaa koko (full) AES-avainaikataulun (key schedule) ja (and) varaa (allocates) tarjoajan tilan (provider state) — silkkaa (pure) hukkaa (waste), kun avain (key) ei koskaan muutu asiakirjan aikana (across the document)
Delphin (Delphi) RTL ei (ships no) sisällä bcryptin (bcrypt) tuontiyksikköä (import unit), joten ilmoita (declare the) tulopisteet (entry points) suoraan (directly). Alla (below) oleva luokka (class) rakentaa (builds) kaiken kryptografisen tilan kerran ja salaa (encrypts) sitten (then) minkä tahansa määrän (any number of) objekteja (objects) ilman vakaan tilan (steady-state) varauksia (allocation):
uses
Winapi.Windows, System.SysUtils, System.Classes;
const
BCRYPT_AES_ALGORITHM = 'AES';
BCRYPT_CHAINING_MODE = 'ChainingMode';
BCRYPT_CHAIN_MODE_CBC = 'ChainingModeCBC';
BCRYPT_OBJECT_LENGTH = 'ObjectLength';
BCRYPT_BLOCK_PADDING = $00000001;
BCRYPT_USE_SYSTEM_PREFERRED_RNG = $00000002;
type
NTSTATUS = Integer;
BCRYPT_HANDLE = Pointer;
function BCryptOpenAlgorithmProvider(out hAlg: BCRYPT_HANDLE; AlgId,
Impl: PWideChar; Flags: ULONG): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptCloseAlgorithmProvider(hAlg: BCRYPT_HANDLE;
Flags: ULONG): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptSetProperty(hObj: BCRYPT_HANDLE; Prop: PWideChar; Input: PByte;
cbInput, Flags: ULONG): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptGetProperty(hObj: BCRYPT_HANDLE; Prop: PWideChar; Output: PByte;
cbOutput: ULONG; out cbResult: ULONG; Flags: ULONG): NTSTATUS; stdcall;
external 'bcrypt.dll';
function BCryptGenerateSymmetricKey(hAlg: BCRYPT_HANDLE;
out hKey: BCRYPT_HANDLE; KeyObj: PByte; cbKeyObj: ULONG; Secret: PByte;
cbSecret: ULONG; Flags: ULONG): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptDestroyKey(hKey: BCRYPT_HANDLE): NTSTATUS; stdcall;
external 'bcrypt.dll';
function BCryptEncrypt(hKey: BCRYPT_HANDLE; Input: PByte; cbInput: ULONG;
Padding: Pointer; IV: PByte; cbIV: ULONG; Output: PByte; cbOutput: ULONG;
out cbResult: ULONG; Flags: ULONG): NTSTATUS; stdcall; external 'bcrypt.dll';
function BCryptGenRandom(hAlg: BCRYPT_HANDLE; Buffer: PByte;
cbBuffer, Flags: ULONG): NTSTATUS; stdcall; external 'bcrypt.dll';
procedure CngCheck(Status: NTSTATUS; const Api: string);
begin
if Status <> 0 then
raise Exception.CreateFmt('%s epäonnistui, NTSTATUS 0x%.8x',
[Api, Cardinal(Status)]);
end;
type
TPdfObjectEncryptor = class
private
FAlg: BCRYPT_HANDLE;
FKey: BCRYPT_HANDLE;
FKeyObject: TBytes; // CNG avain-objekti-työtila (key-object workspace), varattu (allocated) kerran
FScratch: TBytes; // salakirjoituksen raapustuspuskuri (ciphertext scratch), kasvaa (grows) ja pysyy sitten ennallaan (stays)
public
constructor Create(const FileKey: TBytes);
destructor Destroy; override;
procedure EncryptObject(const Plain: TBytes; Dest: TStream);
end;
constructor TPdfObjectEncryptor.Create(const FileKey: TBytes);
var
Mode: string;
ObjLen, Got: ULONG;
begin
inherited Create;
if Length(FileKey) <> 32 then
raise Exception.Create('AES-256 tiedostoavaimen (file key) täytyy olla 32 tavua (bytes)');
CngCheck(BCryptOpenAlgorithmProvider(FAlg, BCRYPT_AES_ALGORITHM, nil, 0),
'BCryptOpenAlgorithmProvider');
Mode := BCRYPT_CHAIN_MODE_CBC;
CngCheck(BCryptSetProperty(FAlg, BCRYPT_CHAINING_MODE,
PByte(PWideChar(Mode)), (Length(Mode) + 1) * SizeOf(WideChar), 0),
'BCryptSetProperty');
CngCheck(BCryptGetProperty(FAlg, BCRYPT_OBJECT_LENGTH, PByte(@ObjLen),
SizeOf(ObjLen), Got, 0), 'BCryptGetProperty');
SetLength(FKeyObject, ObjLen);
// AES-avainaikataulu (AES key schedule) rakennetaan kerran tässä ja käytetään uudelleen jokaista objektia varten
CngCheck(BCryptGenerateSymmetricKey(FAlg, FKey, PByte(FKeyObject), ObjLen,
PByte(FileKey), 32, 0), 'BCryptGenerateSymmetricKey');
end;
destructor TPdfObjectEncryptor.Destroy;
begin
if FKey <> nil then
BCryptDestroyKey(FKey);
if FAlg <> nil then
BCryptCloseAlgorithmProvider(FAlg, 0);
inherited;
end;
procedure TPdfObjectEncryptor.EncryptObject(const Plain: TBytes; Dest: TStream);
var
IV, IVWork: array[0..15] of Byte;
Need, Written: ULONG;
Src: PByte;
begin
// Uusi satunnainen (Fresh random) IV per objekti; se matkaa (travels) selväkielisenä ennen dataa (ahead of the data)
CngCheck(BCryptGenRandom(nil, @IV[0], 16, BCRYPT_USE_SYSTEM_PREFERRED_RNG),
'BCryptGenRandom');
Src := PByte(Plain); // nil tyhjälle syötteelle (empty input) on kelvollinen: pelkän täytteen lohko (padding-only block)
// Kokokysely (Size query): CBC-täyttö (padding) lisää (adds) aina 1..16 tavua, joten Need > Length(Plain)
IVWork := IV; // BCryptEncrypt siirtää (advances) IV-puskuria eteenpäin samalla kun (while it) ketjuttaa (chains)
CngCheck(BCryptEncrypt(FKey, Src, Length(Plain), nil, @IVWork[0], 16,
nil, 0, Need, BCRYPT_BLOCK_PADDING), 'BCryptEncrypt(size)');
if ULONG(Length(FScratch)) < Need then
SetLength(FScratch, Need); // kasvaa kourallisen kertoja, sitten pysyy paikoillaan
IVWork := IV;
CngCheck(BCryptEncrypt(FKey, Src, Length(Plain), nil, @IVWork[0], 16,
PByte(FScratch), Need, Written, BCRYPT_BLOCK_PADDING), 'BCryptEncrypt');
// AESV3-asettelu: 16 tavun IV, sitten pakattu (padded) salakirjoitusteksti (ciphertext)
Dest.WriteBuffer(IV[0], 16);
Dest.WriteBuffer(FScratch[0], Written);
end;
Kolme yksityiskohtaa ovat kantavia (load-bearing). Kokokysely (The size query) — ensimmäinen BCryptEncrypt-kutsu nollatulostepuskurilla (with a nil output buffer) — palauttaa pakatun salakirjoitustekstin pituuden, joka ei (never) koskaan ole yhtä suuri (equal to) syötteen pituuden kanssa (input length); täyttö on determinististä (deterministic), joten (so) voit laskea ((Len div 16) + 1) * 16 itse (yourself) ja puolittaa (halve) kutsumäärän (call count), mutta kysely on dokumentoitu (documented) sopimus (contract). Toiseksi (Second), BCryptEncrypt siirtää (advances) IV-puskuria eteenpäin paikoillaan (in place) samalla kun (as it) se ketjuttaa, joten työkopio (working copy) menee jokaiseen kutsuun (each call) ja koskematon (pristine) IV päätyy (lands in) tulosteeseen (output). Kolmanneksi, FScratch ainoastaan kasvaa (only grows), yltäen aina (up to) tiedoston suurimpaan objektiin asti, minkä jälkeen (after which) silmukka ei (allocates) varaa mitään (nothing)
Minkä arvoinen kahvan (handle) uudelleenkäyttö on (is worth), mitattuna
Tiedosto, joka pakotti (forced) tähän (this) harjoitukseen (exercise), oli 1,8 GB skannattu laina-arkisto (loan archive): 412 000 salattua objektia (encrypted objects), jotka sisälsivät (carrying) 1 710 MB hyötykuormaa (payload), kun (once the) selkokielinen rakenne on vähennetty (subtracted). Sama kone (Same machine), sama tiedosto, NVMe-tallennustila (storage), yksi säie (one thread):
- Kutsukohtainen alustus (Per-call setup) (palveluntarjoaja (provider) avattu (opened) ja avain luotu (generated inside the) apurin sisällä): salausvaihe 71,3 s — 1 710 MB ÷ 71,3 s ≈ 24 MB/s
- Tila nostettu (State hoisted) (yllä oleva luokka (class above)): 9,6 s — 1 710 MB ÷ 9,6 s ≈ 178 MB/s
Ero (The difference) on 61,7 s yli (across) 412 000 kutsun, tai (or) karkeasti (roughly) 150 µs per kutsu käytettynä tarjoajan avaamiseen, ketjutustilan (chaining mode) asettamiseen ja avainaikataulun (key schedule) uudelleenrakentamiseen avaimelle, joka ei koskaan muuttunut (never changed). Mikään tästä ei (None of that) ollut (was) kryptografiaa. AES-NI:n avulla suurten puskureiden (large buffers) CBC-salaus toimii lähellä 1,4 GB/s yhdellä ytimellä, joten (so the) AES-aritmetiikka (arithmetic) itsessään muodostaa noin 1,2 s tuosta (of the) 9,6 sekunnista; suurin osa loppuajasta kuluu kahteen käyttäjätilan (user-mode) BCryptEncrypt-siirtymään (transitions per) objektia kohden sekä (plus) objektikohtaiseen (per-object) IV-luontiin (IV generation). IV:iden niputtaminen (Batching the) — yksi BCryptGenRandom-kutsu, joka täyttää 4 096 niistä (of them) — leikkasi (trimmed the) ajoajan (run to) 8,9 sekuntiin. Sen jälkeen olet API:n objektikohtaisella lattialla (per-object floor), ja jäljellä oleva vipu (remaining lever) on rinnakkaisuus (parallelism): /V 5 -objektit ovat (are) itsenäisiä (independent under the) jaetun tiedostoavaimen (shared file key) alaisuudessa, joten (so) neljä työsäiettä, joilla kullakin oli oma avainobjekti, lyhensivät vaiheen 3,1 sekuntiin ennen kuin tulosteen kirjoittajasta (output writer) tuli (became the) sarjallistamispiste (serialization point)
Täysi uudelleenkirjoitus (Full rewrite) vastaan (versus) inkrementaalinen (incremental) tallennus
Rakeisuus (Granularity) ratkaisee (decides) myös sen, mitä tallennus (save) maksaa (costs). Salauksen lisääminen (Adding encryption to an) olemassa olevaan (existing) selkokieliseen asiakirjaan (plaintext document) kirjoittaa uudelleen (rewrites) jokaisen objektin (every object) määritelmällisesti (by definition): jokainen virta ja merkkijono muuttaa sekä (both) sisältöään että (and) pituuttaan, jokainen ristiviittaussiirtymä (cross-reference offset) siirtyy (moves), eikä (and no) inkrementaalista (incremental) polkua ole (exists). Budjetoi (Budget it) se täytenä peräkkäisenä (sequential) uudelleenkirjoituksena (rewrite) ja (and) kirjoita väliaikaiseen (temporary) tiedostoon, joka (that is) nimetään uudelleen (renamed over) kohteen (target) päälle, koska (because a) kaatuminen (crash) kesken salauksen (mid-encryption) jättää (otherwise leaves a) muuten puoliksi (half-ciphered) salatun tiedoston (file that), jota mikään (no) salasana ei (will) avaa (open)
Käänteinen (The reverse) suunta (direction) on (is the) halpa (cheap one). Kun tiedosto on (is) salattu (encrypted), inkrementaalinen (incremental) päivitys liittää uudet objektit (appends new objects), jotka (encrypted with the) on salattu samalla tiedostoavaimella (same file key), ja jättää jokaisen (every) alkuperäisen (original) tavun (byte) koskemattomaksi (untouched). Hyväksymishuomautuksen (approval annotation) leimaaminen (Stamping an) 2 GB kokoiseen (2 GB) salattuun (encrypted) arkistoon maksaa (costs) kilotavuja (kilobytes of) perään liitettyä tulostetta, ei 2 GB:n kokoista uudelleenkirjoitusta (rewrite). Putkea (pipeline) koskeva seuraus (corollary): salaa (encrypt) kerran (once), työn viimeisenä vaiheena (as the job's last step), ja anna seuraavien kosketusten (subsequent touches) kulkea inkrementaalisten tallennusten varassa (ride incremental saves). Salasanan kierto (password rotation), joka (that also) kierrättää tiedostoavaimen (file key), on jälleen (is a full) täysi (rewrite) uudelleenkirjoitus (again) — aikatauluta se sellaisena (schedule it like one)
Läpimenon (throughput) mittaaminen itseään huijaamatta (without fooling yourself)
Salauksen läpimenoväitteillä (throughput claims) on tapana (tend to) olla vääriä (be wrong in the) osoittajassa (numerator), nimittäjässä (denominator) tai (or) molemmissa. Osoittajan (The numerator) tulisi (should) olla (be) hyötykuormatavuja (payload bytes): niiden virta- ja merkkijonopituuksien summa, jotka tosiasiassa (actually) pusketaan (pushed through) AES:n läpi pakkauksen (compression) jälkeen, minkä (which the) kirjoittaja (writer) voi laskea yhteen (total as it goes) edetessään. Tiedoston koko yliarvioi sen (overstates it) — yllä oleva (above) arkisto (archive) on (is) levyllä 1,8 GB (1.8 GB on disk), mutta vain (but only) 1 710 MB siitä (of it ever) koskettaa salakirjoitusta. Nimittäjän (The denominator) tulisi olla vain (alone) salausvaihe (encryption phase), TStopwatch -rajauksella varustettuna (bracketed with) System.Diagnostics -nimiavaruudesta (from System.Diagnostics), kun jäsentäminen (parsing), purkaminen (deflate) ja (and) levyn I/O jäävät rajauksen (brackets) ulkopuolelle. Jos (Fold) lasket nuo mukaan (those in and the), identtinen salauskoodi mittautuu (measure) useita kertoja hitaammaksi tiedostolla, joka (that merely) pakkautuu (compresses) huonommin. Yllä olevat (The figures above) luvut (figures) ovat vertailukelpoisia (comparable precisely) juuri siksi (because), että (both sides of the) jakolaskun molemmat puolet (division) koskevat (are) vain salausta (encryption-only)
Minkään näistä (None of this) ei tarvitse (has to be) olla koodia (code), jonka omistat (you own). HotPDF paketoi (wraps) saman teknisen toteutuksen (engineering behind) komponenttien (component) ominaisuuksien — ActivateProtection, CryptKeyLength, UseAES256R6 — taakse interaktiivisille (interactive) VCL-sovelluksille oikealla tasolla (at the right altitude), ja sijoitusjärjestyksen ansoista (assignment-order pitfalls) kerrotaan (covered in) HotPDF AES-256 -artikkelissa. Valvomattomille (unattended) putkille PDFlibPas soveltaa (applies) AES-256 revisiota 6 (revision 6 to) olemassa oleviin tiedostoihin (existing files in a) yhdellä (single) EncryptFile-kutsulla tasolla (Strength) 4 ja vahvistaa (verifies) sen jälkeen (afterward), mitä levylle (disk) päätyi (landed on); työnkulku (workflow), joka käydään läpi (walked through in) PDFlibPas -salausauditointiartikkelissa (encryption audit article)
Tässä (here) kuvatut (described) salauspolut (encryption paths) toimitetaan (ship in the) HotPDF Component -kirjaston mukana Delphille ja C++Builderille sekä (and in the) PDFlibPas -kirjaston mukana; molempien tuotteiden sivuilta (product pages) löytyy (carry the) täydellinen (complete) salausviite (encryption reference)