From dc6a11cf6bcb8d80bac88d6030875fe3d76a17de Mon Sep 17 00:00:00 2001 From: Rodrigo Tobar Date: Tue, 20 Dec 2022 13:55:33 +0800 Subject: [PATCH] LibPDF: Treat Encyption's Length item as optional With the StandardSecurityHandler the Length item in the Encryption dictionary is optional, and needs to be given only if the encryption algorithm (V) is other than 1; otherwise we can assume a length of 40 bits for the encryption key. --- Userland/Libraries/LibPDF/CommonNames.h | 1 + Userland/Libraries/LibPDF/Encryption.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibPDF/CommonNames.h b/Userland/Libraries/LibPDF/CommonNames.h index 857bacd7b2..85f878c4be 100644 --- a/Userland/Libraries/LibPDF/CommonNames.h +++ b/Userland/Libraries/LibPDF/CommonNames.h @@ -134,6 +134,7 @@ A(UCR) \ A(UseBlackPTComp) \ A(UserUnit) \ + A(V) \ A(W) \ A(WhitePoint) \ A(Width) \ diff --git a/Userland/Libraries/LibPDF/Encryption.cpp b/Userland/Libraries/LibPDF/Encryption.cpp index f84047314c..396387cd81 100644 --- a/Userland/Libraries/LibPDF/Encryption.cpp +++ b/Userland/Libraries/LibPDF/Encryption.cpp @@ -63,7 +63,21 @@ PDFErrorOr> StandardSecurityHandler::crea auto o = TRY(encryption_dict->get_string(document, CommonNames::O))->string(); auto u = TRY(encryption_dict->get_string(document, CommonNames::U))->string(); auto p = encryption_dict->get_value(CommonNames::P).get(); - auto length = encryption_dict->get_value(CommonNames::Length).get() / 8; + + // V, number: [...] 1 "Algorithm 1 Encryption of data using the RC4 or AES algorithms" in 7.6.2, + // "General Encryption Algorithm," with an encryption key length of 40 bits, see below [...] + // Lenght, integer: (Optional; PDF 1.4; only if V is 2 or 3) The length of the encryption key, in bits. + // The value shall be a multiple of 8, in the range 40 to 128. Default value: 40. + int length_in_bits; + auto v = encryption_dict->get_value(CommonNames::V).get(); + if (encryption_dict->contains(CommonNames::Length)) + length_in_bits = encryption_dict->get_value(CommonNames::Length).get(); + else if (v == 1) + length_in_bits = 40; + else + return Error(Error::Type::Parse, "Can't determine length of encryption key"); + auto length = length_in_bits / 8; + bool encrypt_metadata = true; if (encryption_dict->contains(CommonNames::EncryptMetadata)) encryption_dict->get_value(CommonNames::EncryptMetadata).get();