Skip to content

Encryption (HasSecurity)

The HasSecurity trait on Document provides AES-256 encryption through the Aes256Encryptor engine. TCPDF-Next exclusively implements the PDF 2.0 security handler (AESV3, Revision 6, V5) — RC4 and AES-128 are deliberately removed. Passwords are normalized via SASLprep (RFC 4013) for proper Unicode handling, and key derivation uses Algorithm 2.B (iterative SHA-256/384/512).

Quick Reference

MethodDescription
setProtection()Enable AES-256 encryption with permissions and passwords

Enabling Encryption

php
use Yeeefang\TcpdfNext\Core\Document;

$pdf = Document::create()
    ->setProtection(
        permissions: ['print', 'copy'],
        userPass: 'reader-password',
        ownerPass: 'owner-secret-password',
    )
    ->addPage()
    ->setFont('Helvetica', '', 12)
    ->cell(0, 10, 'This PDF is AES-256 encrypted', newLine: true)
    ->save('encrypted.pdf');

setProtection() returns static, so it chains with every other Document method.

php
$pdf->setProtection(
    array  $permissions = [],   // Permission flags (see table below)
    string $userPass    = '',   // Password required to open the document
    string $ownerPass   = '',   // Password for unrestricted access
);

User Password vs Owner Password

  • User password — the reader must enter this password to open and view the PDF. When empty, the document opens without a prompt but the permission restrictions still apply.
  • Owner password — grants full access to the document, bypassing all permission restrictions. When empty, a random 32-byte owner password is generated internally.

Both passwords are normalized through SASLprep (RFC 4013) before key derivation. This ensures that Unicode passwords like "Pässwörd" are handled consistently across all PDF viewers.

Permission Flags

Pass any combination of these string flags in the $permissions array:

FlagDescription
printAllow printing (low resolution)
modifyAllow content modification
copyAllow text and image extraction
annotateAllow adding annotations
fill-formsAllow form field filling
extractAllow accessibility extraction
assembleAllow page insertion, rotation, and deletion
print-highresAllow high-resolution printing

When $permissions is empty, all operations are restricted (owner password required for any action).

Owner-Only Encryption

To restrict permissions without requiring a password to open:

php
use Yeeefang\TcpdfNext\Core\Document;

$pdf = Document::create()
    ->setProtection(
        permissions: ['print', 'fill-forms'],
        ownerPass: 'admin-password',
    )
    ->addPage()
    ->setFont('Helvetica', '', 12)
    ->cell(0, 10, 'Open freely, but only print and fill forms.', newLine: true)
    ->save('restricted.pdf');

The document opens without a password prompt, but modification, copying, and annotation are blocked unless the owner password is provided.

Security Architecture

TCPDF-Next enforces the strongest PDF encryption standard exclusively:

  • Algorithm: AES-256-CBC (AESV3), Revision 6, V5
  • Key length: 256 bits
  • No legacy: RC4 and AES-128 are deliberately removed

SASLprep Password Normalization

The SaslPrep class (RFC 4013) normalizes passwords with NFKC Unicode normalization, rejects prohibited characters, and enforces bidirectional text constraints. This ensures identical hashes regardless of platform or input method.

Key Derivation — Algorithm 2.B

ISO 32000-2 Algorithm 2.B derives the encryption key through iterative SHA-256/384/512 hashing (up to 64 rounds), providing strong resistance against brute-force attacks.

PDF/A Incompatibility

Encryption is not permitted in PDF/A-compliant documents. If you attempt to call setProtection() on a document that has PDF/A mode enabled, a PdfAException is thrown:

php
use Yeeefang\TcpdfNext\Core\Document;

// This will throw PdfAException
$pdf = Document::create()
    ->setPdfA(true)
    ->setProtection(permissions: ['print'], ownerPass: 'secret');
// -> throws PdfAException: "Encryption is not allowed in PDF/A documents"

If you need both archival compliance and access control, consider using digital signatures with permission restrictions instead.

Complete Example

php
use Yeeefang\TcpdfNext\Core\Document;

$pdf = Document::create()
    ->setTitle('Confidential Report')
    ->setAuthor('Security Team')
    ->setProtection(
        permissions: ['print-highres', 'copy'],
        userPass: 'open-me',
        ownerPass: 'full-access-2026',
    )
    ->addPage()
    ->setFont('Helvetica', 'B', 18)
    ->cell(0, 15, 'Confidential Report', newLine: true)
    ->setFont('Helvetica', '', 12)
    ->multiCell(0, 6, 'This document is protected with AES-256 encryption. '
        . 'Readers can print and copy, but cannot modify or annotate.')
    ->save('confidential-report.pdf');

Released under the LGPL-3.0-or-later License.