Skip to content

Commit

Permalink
BUG: Encrypt / decrypt Stream object dictionaries (#2228)
Browse files Browse the repository at this point in the history
  • Loading branch information
pilotandy authored Oct 7, 2023
1 parent 025f97a commit 8e22f01
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pypdf/_encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(): # Dont forget the Stream dict.
obj2[key] = self.encrypt_object(value)
obj = obj2
elif isinstance(obj, DictionaryObject):
obj2 = DictionaryObject() # type: ignore
Expand All @@ -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(): # Dont forget the Stream dict.
obj[key] = self.decrypt_object(value)
elif isinstance(obj, DictionaryObject):
for key, value in obj.items():
obj[key] = self.decrypt_object(value)
Expand Down
26 changes: 26 additions & 0 deletions tests/test_encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
TESTS_ROOT = Path(__file__).parent.resolve()
PROJECT_ROOT = TESTS_ROOT.parent
RESOURCE_ROOT = PROJECT_ROOT / "resources"
SAMPLE_ROOT = PROJECT_ROOT / "sample-files"


@pytest.mark.parametrize(
Expand Down Expand Up @@ -341,3 +342,28 @@ 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(SAMPLE_ROOT / "023-cmyk-image/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]

0 comments on commit 8e22f01

Please sign in to comment.