Hi,
I found a V4/R4 PDF where the encryption dictionary does not contain a top-level /Length, but the applicable crypt filter does:
qpdf output for the encryption object:
/V 4
/R 4
/CF <<
/StdCF <<
/AuthEvent /DocOpen
/CFM /AESV2
/Length 16
>>
>>
/StmF /StdCF
/StrF /StdCF
There is no top-level /Length entry.
Running:
pdf2john.py sample.pdf
produces:
$pdf$4*4*40*-4*...
The 40 seems to come from:
self.length = self.encrypt_dict.get("/Length", 40)
However, for this V4/R4 PDF the applicable /StdCF crypt filter has:
/Length 16
which corresponds to a 128-bit encryption key.
For comparison, qpdf --show-encryption --password='...' sample.pdf reports:
R = 4
stream encryption method: AESv2
string encryption method: AESv2
file encryption method: AESv2
The resulting 40 in the $pdf$ hash causes john to interpret the PDF as having a 40-bit key, even though the actual encryption uses AES-128.
This then results in the hash not being able to be cracked.
Manually chaning the length to 128 instead of 40 fixes the issue and the password was correctly found by john.
PDF metadata:
Creator: Aspose Pty Ltd.
Producer: PDFsharp 6.2.0 (Original: Aspose.PDF for .NET 26.3.0)
PDF version: 1.7
Encryption: AES (Revision 4 / V4)
The reference also states that /Length is optional:
https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf - section 3.5, page 117
(Optional; PDF 1.4; only if V is 2 or 3) The length of the encryption key, in bits. The value
must be a multiple of 8, in the range 40 to 128. Default value: 40.
Expected behavior
For V4/R4 PDFs using a crypt filter, pdf2john.py should determine the effective key length from the applicable crypt filter when /Length is not present at the top level, rather than unconditionally falling back to the 40-bit default.
KR Alex
Hi,
I found a V4/R4 PDF where the encryption dictionary does not contain a top-level /Length, but the applicable crypt filter does:
qpdfoutput for the encryption object:There is no top-level
/Lengthentry.Running:
pdf2john.py sample.pdfproduces:
$pdf$4*4*40*-4*...The
40seems to come from:self.length = self.encrypt_dict.get("/Length", 40)However, for this V4/R4 PDF the applicable
/StdCFcrypt filter has:/Length 16which corresponds to a 128-bit encryption key.
For comparison,
qpdf --show-encryption --password='...' sample.pdfreports:The resulting 40 in the
$pdf$hash causes john to interpret the PDF as having a 40-bit key, even though the actual encryption uses AES-128.This then results in the hash not being able to be cracked.
Manually chaning the length to 128 instead of 40 fixes the issue and the password was correctly found by john.
PDF metadata:
The reference also states that
/Lengthis optional:https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf - section 3.5, page 117
Expected behavior
For V4/R4 PDFs using a crypt filter,
pdf2john.pyshould determine the effective key length from the applicable crypt filter when/Lengthis not present at the top level, rather than unconditionally falling back to the 40-bit default.KR Alex