diff --git a/pypdf/_encryption.py b/pypdf/_encryption.py index 26065b8e7..87c1162fe 100644 --- a/pypdf/_encryption.py +++ b/pypdf/_encryption.py @@ -79,6 +79,8 @@ def encrypt_object(self, obj: PdfObject) -> PdfObject: obj2 = StreamObject() obj2.update(obj) obj2.set_data(self.stm_crypt.encrypt(b_(obj._data))) + for key, value in obj.items(): + obj2[key] = self.encrypt_object(value) obj = obj2 elif isinstance(obj, DictionaryObject): obj2 = DictionaryObject() # type: ignore @@ -95,6 +97,8 @@ def decrypt_object(self, obj: PdfObject) -> PdfObject: obj = create_string_object(data) elif isinstance(obj, StreamObject): obj._data = self.stm_crypt.decrypt(b_(obj._data)) + for key, value in obj.items(): + obj[key] = self.decrypt_object(value) elif isinstance(obj, DictionaryObject): for key, value in obj.items(): obj[key] = self.decrypt_object(value) diff --git a/resources/cmyk_image.pdf b/resources/cmyk_image.pdf new file mode 100644 index 000000000..c4ea523b3 Binary files /dev/null and b/resources/cmyk_image.pdf differ diff --git a/tests/test_encryption.py b/tests/test_encryption.py index f5fe747e0..a9f3b029c 100644 --- a/tests/test_encryption.py +++ b/tests/test_encryption.py @@ -341,3 +341,30 @@ def test_aes_decrypt_corrupted_data(): aes = CryptAES(secrets.token_bytes(16)) for num in [0, 17, 32]: aes.decrypt(secrets.token_bytes(num)) + + +def test_encrypt_stream_dictionary(pdf_file_path): + user_password = secrets.token_urlsafe(10) + + reader = PdfReader(RESOURCE_ROOT / "cmyk_image.pdf") + page = reader.pages[0] + original_image_obj = reader.get_object(page.images["/I"].indirect_reference) + + writer = PdfWriter() + writer.add_page(reader.pages[0]) + writer.encrypt( + user_password=user_password, + owner_password=None, + algorithm="RC4-128", + ) + with open(pdf_file_path, "wb") as output_stream: + writer.write(output_stream) + + reader = PdfReader(pdf_file_path) + assert reader.is_encrypted + assert reader.decrypt(user_password) == PasswordType.OWNER_PASSWORD + page = reader.pages[0] + decrypted_image_obj = reader.get_object(page.images["/I"].indirect_reference) + + assert decrypted_image_obj["/ColorSpace"][3] == original_image_obj["/ColorSpace"][3] +