Encrypt a PDF with AES-256 and set permissions
At a glance
Section titled “At a glance”Use this recipe to encrypt a document with AES-256. You set a user password, an owner password, and a permission bitmask that restricts allowed operations. The recipe follows examples/22-protection.php.
Reproducibility — why this recipe is
structural, notbitwise. An AES-256 PDF is never byte-identical between runs, even with the same input and passwords. Before it derives the file-encryption key, the revision-6 standard security handler generates 16 fresh random bytes (the user/owner validation and key salts) for each encryption with a strong random number generator (ISO 32000-2 §7.6.4, Algorithm 2.B). AES-256-CBC uses a random initialization vector for each object. The trailer/IDis also an array of two byte strings. Its first element is a permanent identifier derived from the file at creation time (ISO 32000-2 §14.4). The reproducibility profile is thereforestructural: before it compares two runs, the harness canonicalises the encryption salts/IV, object order, and trailer/ID, instead of asserting an impossible byte match.
Prerequisites
Section titled “Prerequisites”- Core installed:
composer require nextpdf/core:^3. - The
opensslPHP extension, which the AES-256 encryptor requires.
Recipe
Section titled “Recipe”- Create the document.
- Call
setEncryption()beforeaddPage(). The encryptor must be ready before any content object is written. - Pass a user password (required to open the document), an owner password (for full access), and a permission bitmask.
- Add content, and save. The writer encrypts each object body.
Full example
Section titled “Full example”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Permission bits (ISO 32000-2, encryption dictionary P entry):// bit 3 (4) allow printing// bit 4 (8) allow content modification// bit 5 (16) allow text extraction / copying// bit 6 (32) allow annotation and form editing// Grant printing only:$permissions = 4;
$doc = Document::createStandalone();$doc->setTitle('Encrypted Document');
// setEncryption() MUST run before addPage(). Order matters.$doc->setEncryption( userPassword: 'open-me', ownerPassword: 'owner-secret', permissions: $permissions,);
$doc->addPage();$doc->setFont('helvetica', '', 12);$doc->cell(0, 10, 'This document is encrypted with AES-256.', newLine: true);
$doc->save(__DIR__ . '/encrypted.pdf');
echo "Wrote encrypted.pdf (AES-256, printing only)\n";Expected output
Section titled “Expected output”Wrote encrypted.pdf (AES-256, printing only)When you open encrypted.pdf, the reader prompts for a password. The user password opens the document with the restricted permission set. The owner password opens it with full access.
Edge cases
Section titled “Edge cases”- Call order.
setEncryption()afteraddPage()does not encrypt earlier content retroactively. Always configure encryption first. - Owner password default. When the owner password is empty, the engine reuses the user password as the owner password. Set distinct passwords when these roles must differ.
- Permission semantics — boundary. Conforming readers honor the permission bits. They are not cryptographically enforced: a reader that ignores the bits, or a tool used with the owner password, can perform restricted operations. Treat permissions as a policy signal for cooperating software, not as access control that withstands a determined party.
- PDF/A conflict. PDF/A prohibits the
Encrypttrailer key. CallingsetEncryption()on a PDF/A document, in either order, throws an incompatibility exception. See PDF/A-4 conformance gate. - AES-256-GCM.
useAesGcm()opts in to ISO/TS 32003 GCM bulk encryption when the host OpenSSL or libsodium offers the cipher. Otherwise, it throwsInvalidConfigException.
Conformance
Section titled “Conformance”| Statement | Spec | Clause | reference_id |
|---|---|---|---|
| The standard security handler defines the encryption algorithm and key length. | ISO 32000-2 | §7.6 | |
The encryption dictionary P entry carries the permission bits. | ISO 32000-2 | §7.6 |
Encryption protects content confidentiality from parties without the password. Permission bits are advisory to readers and, on their own, do not prevent a non-conforming tool from acting.