PDFiumPas writes ISO/TS 32003 encryption through SaveAsEncrypted: set Revision to erR7 and every string and stream is protected with AES-256 in GCM mode, the authenticated cipher PDF 2.0 gained in 2023. Set EnableIntegrityProtection as well and the document also carries a standalone PDF MAC token, which ValidatePdfMac checks on the reading side
Those are two different protections that people routinely conflate. GCM authenticates each encrypted value. The MAC authenticates the document as a whole. You want both, for different reasons
What does GCM add that CBC never provided?
Authentication of the ciphertext. AES-256 in CBC mode, the AESV3 scheme in ISO 32000-2, keeps content confidential and says nothing about whether it arrived unmodified. CBC is malleable in specific, well-studied ways: an attacker who can flip bits in the ciphertext produces predictable changes in the plaintext of the following block, and nothing in the format notices
GCM closes that. Each encrypted value carries a 16-byte authentication tag, serialised in full as ISO/TS 32003 requires, and decryption fails rather than returning altered plaintext when the tag does not match. In PDF terms, a tampered string or stream in an AESV4 document is a hard error at the point of use, not a strange value that propagates into your application. The Encrypt dictionary marks this with /CFM /AESV4 and V 6 / R 7, alongside an extensions entry declaring /ExtensionLevel 32003 and /ExtensionRevision (:2023)
Three revisions, three ecosystems
TPdfEncryptionRevision offers erR5, erR6 and erR7, and the choice is a compatibility decision more than a cryptographic one. R5 is the original AES-256 scheme published as a PDF 1.7 extension, with a single SHA-256 password hash, and it opens in essentially anything from the last fifteen years. R6 is the hardened key derivation standardised in ISO 32000-2, using the iterating SHA-256/384/512 construction of algorithm 2.B, and it is what a current PDF 2.0 or PDF/A-4 workflow expects. R7 is ISO/TS 32003, using the same 2.B derivation with AES-GCM as the cipher
Reader support runs in exactly that order, and R7 support is still thin outside current mainstream viewers. This is the same trade-off that governs any PDF 2.0 feature: the newest option is the best engineering and the narrowest audience. Decide by who has to open the file, and if that answer is "a records system nobody has updated since 2019", the answer is R5 regardless of what the security policy prefers
uses
PDFium, FPdfEncrypt;
var
Pdf: TPdf;
Opts: TPdfEncryptOptions;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'quarterly-report.pdf';
Pdf.LoadDocument;
Opts := TPdfEncryptOptions.Default;
Opts.UserPassword := 'open-secret';
Opts.OwnerPassword := 'admin-secret';
Opts.EncryptMetadata := True;
Opts.Revision := erR7; // ISO/TS 32003 AESV4-GCM
Opts.EnableIntegrityProtection := True; // standalone PDF MAC token
if not Pdf.SaveAsEncrypted('quarterly-report.enc.pdf', Opts) then
raise Exception.Create('Encrypted save failed');
finally
Pdf.Free;
end;
end;
Why a document MAC on top of an authenticated cipher?
Because GCM tags protect the values, not the arrangement of the values. Every string and stream in an AESV4 document is individually authenticated, yet the cross-reference table, the object numbering and the trailer are structure, not encrypted content. An attacker cannot forge a stream, but nothing in the cipher alone stops them from rearranging which objects the document points at, or splicing objects from an earlier revision of the same file
The standalone PDF MAC token addresses that layer. PDFiumPas derives it from the file encryption key with a dedicated 32-byte /KDFSalt recorded in the Encrypt dictionary, so possession of the password is what lets a reader confirm the token. The result is a single answer to a single question: is this document, as a whole, the document that was written
var
Pdf: TPdf;
Mac: TPdfMacValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.Password := 'open-secret';
Pdf.FileName := 'quarterly-report.enc.pdf';
Pdf.LoadDocument;
Mac := Pdf.ValidatePdfMac('open-secret');
case Mac.Status of
pmvsValid: ProcessDocument(Pdf);
pmvsNotPresent: ProcessWithWarning(Pdf); // no token in this file
pmvsInvalid: Quarantine(Mac.MessageText); // tampered or truncated
pmvsUnsupported: RouteForManualReview(Mac.MessageText);
end;
finally
Pdf.Free;
end;
end;
The four status values need four different responses, and collapsing them into a boolean loses the distinction that matters. pmvsNotPresent means the file simply has no token, which describes almost every encrypted PDF written before 2024 and is not evidence of anything. pmvsInvalid means a token is present and does not verify, which is a genuine finding and should stop processing. pmvsUnsupported means the token exists in a shape this build does not implement, which is a compatibility gap, not an attack. Treating "not present" as "invalid" would quarantine your entire back catalogue on the first day
What encryption still does not do
Permission flags remain what they have always been: a request to conforming software, not a control. The /P bits from ISO 32000-1 Table 22 that disallow printing or extraction are honoured by well-behaved viewers and ignored by everything else, and anyone holding the user password already holds the decrypted content. Encryption is the boundary; permissions describe intent inside it
Two operational details are worth planning for. First, encryption and later modification interact: appending an incremental update to an encrypted document has rules of its own, covered in incremental updates on encrypted PDFs, and a MAC token is a document-level statement that a careless append will invalidate. Second, the GCM construction uses a deterministic IV counter, and PDFiumPas raises rather than reusing a counter value if that space were ever exhausted, because nonce reuse in GCM is catastrophic in a way silent wraparound would hide
Choosing between the three revisions in practice
Write down who opens the file, then pick. For internal distribution where every reader is a current viewer under your control, R7 with integrity protection is the strongest option available and there is no reason not to use it. For documents leaving the organisation, R6 is the defensible default: it is standardised in ISO 32000-2 rather than in a technical specification on top of it, and support is broad. For archives and legacy consumers, R5 is the only choice that reliably opens, and you should record why in the same place you record the rest of your retention policy
Whichever you pick, verify the output rather than trusting the call succeeded. Re-open the encrypted file, check ValidatePdfMac, and confirm the declared version is what you expect, using the version conformance checks in exact PDF version conformance. A broader intake checklist for untrusted documents is in auditing PDF security risks
PDFiumPas is a Delphi and Lazarus component around the PDFium engine with the PDF 2.0 encryption stack implemented natively in Pascal, so AES-256, GCM and the MAC token need no external crypto DLL. The encryption API is documented on the PDFium Delphi component page