Versleuteling: AES-256 (CBC) en AES-256-GCM
In een oogopslag
Sectie met titel “In een oogopslag”Core versleutelt Portable Document Format (PDF)-bestanden met AES-256 (Advanced Encryption Standard met 256-bits sleutels) volgens de ISO 32000-2:2020 §7.6 Standard security handler. De standaardmodus is V=5 / R=6 / AESV3 (AES-256-CBC, Cipher Block Chaining). De optionele geauthenticeerde modus is het ISO/TS 32003:2023 V=6 / R=7 AES-256-GCM-pad (Galois/Counter Mode). Deze pagina legt de sleutelafleiding, het wire-formaat, de permissiegrens en de implementatielimieten vast.
Installeren
Sectie met titel “Installeren”composer require nextpdf/core:^3Het standaardpad vereist de openssl-extensie. Het AES-256-GCM-pad gebruikt openssl of ext-sodium. Op hosts zonder AES-NI-hardware ondersteunt libsodium GCM niet; Core valt terug op de tragere OpenSSL-implementatie zonder het algoritme te wijzigen.
Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”De standaardhandler gebruikt de V=5 / R=6 Standard security handler met het AESV3-crypt filter. Als u setEncryption() aanroept, genereert Core een willekeurige 256-bits bestandssleutel via de cryptografisch veilige willekeurige bron van het platform (random_bytes()). De sleutel is 32 bytes en komt overeen met de sleutellengte van FIPS 197. Core versleutelt inhoud per object met AES-256-CBC. Core plaatst de 16-byte initialisatievector vóór elke ciphertext, zoals ISO 32000-2:2020 §7.6.4 voorschrijft.
Sleutelafleiding volgt Algorithm 2.B voor revisie 6. Core normaliseert het wachtwoord eerst met SASLprep (RFC 4013) en kort het vervolgens op een tekengrens in tot 127 UTF-8-bytes, zoals ISO 32000-2:2020 §7.6.4.3.3 voorschrijft. Het berekent de afgeleide hash met een geïtereerde SHA-256 / SHA-384 / SHA-512-routine die wordt aangestuurd door een AES-128-CBC-stap, waardoor het offline raden van wachtwoorden duurder wordt. Core genereert de user-, owner- en per-sleutel-salts één keer per encryptor-instantie, zodat één instantie deterministische dictionary-bytes produceert, een voorwaarde voor een writer die meerdere passes uitvoert.
useAesGcm() schakelt het optionele AES-256-GCM-pad in. Het implementeert het ISO/TS 32003:2023 V=6 / R=7 AESV4-crypt filter. De cipher is AES-256-GCM met parameters uit NIST SP 800-38D. Voor elk versleuteld object bestaat de wire-indeling uit een 12-byte IV, de ciphertext en een 16-byte authenticatietag. De additional authenticated data is leeg, zoals het TS 32003 §5.2-profiel voorschrijft. Bij decryptie verifieert Core de tag en werpt het TamperedDataException bij een mismatch; het geeft nooit plaintext terug na een mislukte tagverificatie. Dit pad voegt detectie van wijzigingen toe die het standaard CBC-pad zelf niet biedt.
Het GCM-pad volgt de discipline van IV-uniciteit in NIST SP 800-38D §8. De bovenste 4 bytes van de IV vormen een per-instantie vast veld dat bij de constructie uit een willekeurige bron wordt ingesteld. De onderste 8 bytes vormen een big-endian teller die na elke uitgegeven IV wordt opgehoogd. Dit volgt de deterministische constructiebenadering in §8.2.1, behalve dat het vaste veld wordt gerandomiseerd om botsingen tussen documenten te voorkomen in plaats van te worden opgesomd. Een tweede waarborg registreert elke uitgegeven IV in een botsingsverzameling en werpt NonceReuseException als een waarde opnieuw verschijnt. Telleroverloop werpt eveneens NonceReuseException, omdat overloop de faalmodus met IV-hergebruik is waarvoor §8 waarschuwt.
Op het GCM-pad gelden twee lengtegrenzen. Het plaintext-plafond per object is 2^39 − 256 bytes, de per-invocatiegrens afgeleid in NIST SP 800-38D §5.2.1.1. Grotere invoer werpt een lengte-exceptie met richtlijnen om de gegevens over meerdere objecten te verdelen. De veiligheidsgrens voor invocaties is 2^32 aanroepen per sleutel. assertWithinSafetyBound() is een optionele controle die GcmInvocationLimitExceededException werpt, zodat een aanroeper de documentsleutel kan roteren vóór de §8.3-drempel. NIST SP 800-57 Part 1 §4 behandelt deze beslissing over de sleutellevensduur als een implementatieverantwoordelijkheid.
Permissievlaggen zijn adviserend. Core schrijft het bitmasker naar de versleutelde /Perms-entry en de /P-waarde en herstelt deze bij het lezen met validatePerms(), dat fail-closed reageert op een corrupte marker. Van een conforme reader wordt verwacht dat hij de vlaggen respecteert. De vlaggen worden niet door cryptografie afgedwongen: een processor die de decryptiesleutel bezit en de bits negeert, kan de inhoud lezen, kopiëren of wijzigen. Beschrijf permissievlaggen als een readerconventie, niet als toegangscontrole.
API-oppervlak
Sectie met titel “API-oppervlak”| Type | Soort | Belangrijkste members | Stabiliteit | Sinds |
|---|---|---|---|---|
Aes256Encryptor | class | encrypt(), decrypt(), encryptForObject(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms(), getEncryptionKey() | stable | 1.0.0 |
Aes256GcmEncryptor | class | encrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount(), isAvailable() | stable | 2.18.0 |
KeyMaterial | final readonly class | generate(), exposeKey(), fingerprint() | stable | 2.18.0 |
EncryptedPayloadSpec | final readonly class | toDict() | stable | 2.18.0 |
CryptoCapabilities | final class | hasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile() | stable | 2.0.0 |
NonceReuseException | exception | — | stable | 2.18.0 |
TamperedDataException | exception | — | stable | 2.18.0 |
DecryptionFailedException | exception | — | stable | 2.18.0 |
GcmInvocationLimitExceededException | exception | — | stable | 3.0.0 |
Codevoorbeeld — Snelstart
Sectie met titel “Codevoorbeeld — Snelstart”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// AES-256-CBC, V=5/R=6. Call before addPage().$doc->setEncryption( userPassword: 'demo', ownerPassword: 'admin', permissions: 4, // printing only; copy/modify denied for a conforming reader);
$doc->addPage();$doc->setFont('helvetica', '', 12);$doc->cell(0, 8, 'Confidential', newLine: true);
$doc->save(__DIR__ . '/output/22-protection.pdf');Codevoorbeeld — Productie
Sectie met titel “Codevoorbeeld — Productie”<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Security\CryptoCapabilities;use NextPDF\Security\Encryption\Aes256GcmEncryptor;use NextPDF\Security\Exception\TamperedDataException;use NextPDF\Security\KeyMaterial;use Psr\Log\LoggerInterface;
final readonly class AuthenticatedBlobCipher{ public function __construct(private LoggerInterface $logger) {}
/** * Seal a payload with AES-256-GCM and return the wire-format bytes. * * @param non-empty-string $plaintext The payload to protect. * * @return non-empty-string IV(12) || ciphertext || tag(16). */ public function seal(string $plaintext, KeyMaterial $key): string { if (!CryptoCapabilities::hasAesGcm()) { throw new \RuntimeException('Host cannot perform AES-256-GCM.'); }
$cipher = new Aes256GcmEncryptor($key); // Opt-in NIST SP 800-38D §8.3 key-rotation guard. $cipher->assertWithinSafetyBound();
$wire = $cipher->encrypt($plaintext);
$this->logger->info('Payload sealed', [ 'key_fingerprint' => $key->fingerprint(), 'invocations' => $cipher->invocationCount(), ]);
return $wire; }
/** * Open a sealed payload; a modified payload raises, never returns plaintext. * * @param non-empty-string $wire IV(12) || ciphertext || tag(16). */ public function open(string $wire, KeyMaterial $key): string { try { return (new Aes256GcmEncryptor($key))->decrypt($wire); } catch (TamperedDataException $e) { $this->logger->warning('Tampered payload rejected', [ 'key_fingerprint' => $key->fingerprint(), ]);
throw $e; } }}De cipher controleert de hostcapaciteit, past de optionele invocatiewaarborg toe, logt alleen de niet-omkeerbare key fingerprint en werpt afwijzingen wegens manipulatie opnieuw in plaats van verdachte bytes terug te geven.
Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”- Het standaardpad voor AES-256-CBC biedt alleen vertrouwelijkheid. Het detecteert zelf geen gewijzigde ciphertext. Gebruik het AES-256-GCM-pad wanneer u detectie van wijzigingen nodig hebt.
useAesGcm()werpt een exceptie als de PDF/A-modus actief is, en ook als nochopensslnochext-sodiumAES-256-GCM biedt. Vang beide gevallen op en presenteer een actiegerichte melding aan de operator.- Op hosts zonder AES-NI ondersteunt libsodium GCM niet. Core valt terug op OpenSSL GCM, dat wel correct maar trager is; de doorvoer daalt, niet de veiligheid.
- Het GCM-plaintext-plafond per object is
2^39 − 256bytes. Grotere invoer werpt een lengte-exceptie; verdeel de inhoud over meerdere objecten metencryptStream(). - Een
KeyMaterial-instantie moet exact 32 bytes zijn. De constructie wijst een verkeerde lengte af in plaats van deze af te kappen. - Het readerpad (
verifyUserPassword(),verifyOwnerPassword(),validatePerms()) gebruikt constant-time-vergelijking voor cryptografisch materiaal en reageert fail-closed op een corrupte permissiemarker.
Prestaties
Sectie met titel “Prestaties”AES-256-CBC-versleuteling per object gebruikt één OpenSSL-aanroep en is O(n) ten opzichte van de objectbody. Sleutelafleiding voert de geïtereerde Algorithm 2.B-routine één keer per encryptor-instantie uit; de kosten zijn begrensd en constant per document. Het streaming-pad van AES-256-GCM verdeelt de invoer in chunks van 16 MiB, waardoor het live-heapgebruik ongeacht de totale invoergrootte tot ongeveer 64 MB wordt begrensd en onder het gedocumenteerde piekbudget van 64 MB blijft. Elk GCM-object voegt 28 bytes overhead toe (12-byte IV plus 16-byte tag). AES-NI-hardware verbetert de GCM-doorvoer aanzienlijk; zonder deze hardware daalt alleen de doorvoer.
Beveiligingsnotities
Sectie met titel “Beveiligingsnotities”Dit versleutelingsoppervlak heeft een expliciet bedreigingsmodel. SASLprep-normalisatie en de geïtereerde revisie-6-sleutelafleiding verhogen de kosten van het offline raden van wachtwoorden, maar een zwak wachtwoord blijft het dominante restrisico. Geen enkele afleiding neemt dat risico weg. Het GCM-pad detecteert wijzigingen in ciphertext via tagverificatie; het standaard CBC-pad doet dat niet. Op het GCM-pad voorkomen een teller plus een botsingsverzameling IV-hergebruik, consistent met de IV-discipline van NIST SP 800-38D §8.1. Bij telleroverloop wordt geweigerd in plaats van gewrapt. KeyMaterial-redactie en het #[\SensitiveParameter]-attribuut op wachtwoorden beperken openbaarmaking van sleutels via logs. Afgeleid sleutelmateriaal wordt na gebruik op nul gezet waar het platform dit toestaat.
Ook de grens is expliciet. Core past AES-256-versleuteling toe zoals gedefinieerd in ISO 32000-2:2020 §7.6 en, voor het optionele pad, ISO/TS 32003:2023 §5.2. Effectieve bescherming hangt af van de sterkte van het wachtwoord, het sleutelbeheer, de implementatieomgeving en de gebruikte reader. Conforme readers respecteren permissievlaggen, maar cryptografie dwingt ze niet af. De AES-ECB-stap die voor de /Perms-waarde wordt gebruikt, is voorgeschreven door ISO 32000-2:2020 §7.6.4.4.10 voor één blok van 16 bytes. Die stap is geen modus voor algemeen gebruik. Core biedt een controle voor sleutelrotatie vóór de 2^32-invocatiegrens, maar dwingt deze niet standaard af; die rotatie is een implementatieverantwoordelijkheid.
Datalocatie en PII-maatregelen
Sectie met titel “Datalocatie en PII-maatregelen”Versleuteling en decryptie verlopen in-process; geen documentbytes, geen wachtwoord en geen sleutelwaarde verlaten de host via dit oppervlak. De GCM-IV-botsingsverzameling indexeert op een niet-omkeerbare key fingerprint, niet op sleutelbytes. Als een implementatie de sleutel achter een extern key-management-systeem of een PKCS#11-token plaatst, is die backend verantwoordelijk voor de datalocatie; OASIS PKCS#11 v3.1 C_GenerateKey is het contractpunt voor token-residente sleutelgeneratie.
Veilige telemetrie en logscrubbing
Sectie met titel “Veilige telemetrie en logscrubbing”Log de beleidsnaam en de key fingerprint van 8 tekens, nooit de sleutel of het wachtwoord. KeyMaterial::__toString() en __debugInfo() geven een geredigeerde placeholder terug. Excepties uit dit oppervlak bevatten een operatielabel en een fingerprint, geen sleutelbytes. De GCM-invocatieteller is veilige telemetrie voor dashboards voor sleutelrotatie.
Bedreigingsmodel
Sectie met titel “Bedreigingsmodel”| Bedreiging | Maatregel in Core | Restgrens |
|---|---|---|
| Offline wachtwoorden raden | SASLprep plus geïtereerde revisie-6-afleiding | Een zwak wachtwoord is nog steeds het dominante risico |
| Wijziging van ciphertext | GCM-tagverificatie (optioneel pad) | CBC-pad biedt alleen vertrouwelijkheid |
| IV-hergebruik (GCM) | Willekeurig vast veld plus teller plus botsingsverzameling; overloop weigert | — |
| Te lange GCM-plaintext | Lengtecontrole bij 2^39 − 256; richtlijnen voor partitionering | Aanroeper moet grote invoer streamen |
| Overmatig sleutelgebruik (GCM) | assertWithinSafetyBound() bij 2^32 | Optioneel; standaard niet afgedwongen |
| Omzeilen van permissievlaggen | Geen — vlaggen zijn adviserend | Een niet-conforme reader negeert de vlaggen |
| Openbaarmaking van sleutels via logs | KeyMaterial-redactie; #[\SensitiveParameter] | Een aanroeper die exposeKey() logt, ondermijnt dit |
Gedrag in FIPS-modus
Sectie met titel “Gedrag in FIPS-modus”Core is geen FIPS-gevalideerde cryptografische module en is niet FIPS-gecertificeerd. CryptoCapabilities::detectFipsMode() is een best-effort-sonde die active, absent of indeterminate rapporteert. assertFipsAvailableForProfile() reageert fail-closed wanneer een FIPS-profiel is geselecteerd op een host die geen FIPS-provider aantoont. Het versleutelingsoppervlak werkt in een FIPS-compatibele modus wanneer het draait tegen een host-OpenSSL-build die een FIPS-gevalideerde provider heeft geladen. Een gevalideerde, gecertificeerde status is een Enterprise-aangelegenheid.
Conformiteit
Sectie met titel “Conformiteit”| Claim | Standaard | Clausule | Bewijs |
|---|---|---|---|
| Elke GCM-IV is uniek per invocatie via een deterministische constructie van een vast veld plus een teller. | NIST SP 800-38D | §8.2.1 | |
| De IV-constructiediscipline voorkomt hergebruik over invocaties heen met één sleutel. | NIST SP 800-38D | §8.1 | |
| Het plaintext-plafond per object komt overeen met de per-invocatielengtegrens. | NIST SP 800-38D | §5.2.1.1 | |
| Sleutelcryptoperiode en -rotatie vallen onder de implementatieverantwoordelijkheid. | NIST SP 800-57 Part 1 Rev. 5 | §4 | |
| De AES-bestandssleutel is 256 bits en komt overeen met de sleutellengte van de standaard. | FIPS 197 | §4.2.1 | |
| Token-residente sleutelgeneratie is het integratiepunt voor externe sleutelopslag. | OASIS PKCS#11 v3.1 | C_GenerateKey |
ISO 32000-2:2020 §7.6 en ISO/TS 32003:2023 §5.2 vormen de normatieve basis voor de hier gedocumenteerde handlers. De tekst daarvan is licentiebeperkt. Deze pagina parafraseert die standaarden, citeert clausules op nummer en neemt er geen tekst uit over. De Algorithm 2.B-standaardtest en de externe-oracle-fixture in de evidence-trailer van de pagina leveren het geverifieerde runtime-bewijs voor byte-exacte sleutelafleiding.
Commerciële context
Sectie met titel “Commerciële context”Core levert het standaard AES-256-CBC-pad, het optionele AES-256-GCM-pad, een lokaal sleuteloppervlak en de cryptobeleidspoort. De Enterprise-editie voegt een HSM/PKCS#11-sleutelbeheerbackend en een cryptobeleidsprofiel in FIPS-modus toe achter dezelfde contracten. De openbare application programming interface (API) is identiek; de sleutelbeheerbackend en de beleidsimplementatie verschillen.
Zie ook
Sectie met titel “Zie ook”- Security — het overzicht van de beveiligingsmodule en de permissiegrens.
- Contracts / Security Policy — het cryptobeleidscontract dat als poort voor de cipher fungeert.
- Security / Signing — handtekeningen en tijdstempels, het bijbehorende crypto-oppervlak.
- Conformance — PDF/A-verbod op de
Encrypt-sleutel.