https://bugs.documentfoundation.org/show_bug.cgi?id=174024
Bug ID: 174024
Summary: PDF export with AES-256 encryption (PDF 2.0): stream
/Length is the unencrypted length
Product: LibreOffice
Version: 26.8.1.1 release
Hardware: All
OS: All
Status: UNCONFIRMED
Severity: normal
Priority: medium
Component: Printing and PDF export
Assignee: [email protected]
Reporter: [email protected]
Created attachment 209139
--> https://bugs.documentfoundation.org/attachment.cgi?id=209139&action=edit
aes256-export.pdf: output of the export (open password 'user', permissions
password 'owner'); objects 8 and 13 have /Length 264 and 282 but contain 288
and 304 bytes
When a document is exported to PDF 2.0 with a password (AES-256, standard
security handler V5/R6), every stream's /Length entry gives the length of the
plaintext, not of the encrypted data written to the file. AES-256 adds a
16-byte IV and up to 16 bytes of padding, so each stream is 17-32 bytes longer
than its /Length says.
PDF readers that trust /Length (as ISO 32000-2 7.3.8.2 requires) read a
truncated stream and then fail to find "endstream". Lenient readers (macOS
Preview/PDFKit) recover by searching for "endstream", which is why the problem
is easy to miss.
RC4 encryption (PDF 1.x export with a password) is not affected: an RC4 export
of the same document has correct lengths, since RC4 doesn't change the data
length.
Steps to reproduce:
1. Use repro.html (I'll attach it right after filing; any document will do).
2. Export it to PDF 2.0 with an open password, e.g.:
soffice --headless --infilter="HTML (StarWriter)" --convert-to
'pdf:writer_pdf_Export:{"SelectPdfVersion":{"type":"long","value":"20"},"EncryptFile":{"type":"boolean","value":"true"},"DocumentOpenPassword":{"type":"string","value":"user"},"RestrictPermissions":{"type":"boolean","value":"true"},"PermissionPassword":{"type":"string","value":"owner"}}'
repro.html
3. Compare each stream's /Length with the number of bytes between "stream" and
"endstream".
Actual results:
Every stream with a direct /Length is short by exactly the AES overhead. In the
resulting PDF (attached as aes256-export.pdf; open password "user", permissions
password "owner"):
- object 8: /Length 264, actual 288 bytes (16-byte IV + 264 padded to 272)
- object 13: /Length 282, actual 304 bytes (16-byte IV + 288)
Expected results:
/Length equals the number of encrypted bytes actually written (288 and 304
above).
Additional information:
The fix is presumably to set /Length after encryption, or to account for the
AES IV and PKCS#7 padding when the length is written. Related: bug 107007 (the
request for AES encryption in PDF export).
Found while testing a PDF reader against encrypted PDFs from several producers
(Quartz, Ghostscript, Adobe, LibreOffice). LibreOffice 26.8.1.1, macOS 15.8.1;
the export code isn't platform-specific.
--
You are receiving this mail because:
You are the assignee for the bug.