Hoe te werken met de PDF-encryptie-engine in Python
Aspose.PDF FOSS voor Python (import aspose_pdf) implementeert PDF-wachtwoordbeveiliging op byte-niveau via een kleine interne engine-klasse, EncryptionUtils, in aspose_pdf.engine.encryption. Hier bevinden zich de AES-CBC cipher en de sleutelafleidingsalgoritmen van de PDF Standard Security Handler (ISO 32000 Revisies 2 tot en met 6), onafhankelijk van de high-level Document API. Deze gids installeert het pakket en loopt drie engine-taken door: het versleutelen en ontsleutelen van ruwe bytes met AES-CBC, het afleiden van Standard Security Handler-sleutels voor een wachtwoord (Revisies 2-4), en het afleiden van AES-256 sleutels voor Revisie 5/6-documenten.
Stapsgewijze handleiding
Stap 2: Importeer vereiste klassen
EncryptionUtils wordt niet opnieuw geëxporteerd vanuit het top-level aspose_pdf pakket — importeer het direct vanuit de engine.encryption submodule:
import os
from aspose_pdf.engine.encryption import EncryptionUtilsStap 3: Versleutel en ontsleutel gegevens met AES-CBC
encrypt_aes_cbc en decrypt_aes_cbc werken direct op elke 16-, 24- of 32-byte sleutel (AES-128, AES-192 of AES-256) zonder gebruik te maken van wachtwoordgebaseerde sleutelafleiding. encrypt_aes_cbc past intern PKCS7-padding toe, en decrypt_aes_cbc verwijdert deze.
key = os.urandom(32) # AES-256; 16- and 24-byte keys are also accepted
plaintext = b"Confidential PDF content"
ciphertext = EncryptionUtils.encrypt_aes_cbc(key, plaintext)
decrypted = EncryptionUtils.decrypt_aes_cbc(key, ciphertext)
assert decrypted == plaintext
print("Roundtrip OK, ciphertext length:", len(ciphertext))Stap 4: Standaardbeveiligingshandler-sleutels afleiden voor een wachtwoord (Revisies 2-4)
compute_owner_key_v4 berekent de Owner-wachtwoordwaarde (O) volgens Algoritme 3.3, en compute_user_key_v4 berekent de User-wachtwoordwaarde (U) en de bestandsversleutelingssleutel volgens Algoritme 3.4/3.5. verify_password_v4 leidt de sleutel opnieuw af van een kandidaatwachtwoord zodat u kunt bevestigen dat het document wordt geopend voordat u het vertrouwt.
owner_password = "owner-secret"
user_password = "user-secret"
key_length = 16 # 128-bit (AES/RC4); Revision 2 uses 5 (40-bit)
revision = 4
file_id = os.urandom(16)
permissions = -4 # standard PDF permissions value
o_value = EncryptionUtils.compute_owner_key_v4(
owner_password, user_password, key_length, revision
)
u_value, encryption_key = EncryptionUtils.compute_user_key_v4(
user_password, o_value, permissions, file_id, key_length, revision
)
verified_key = EncryptionUtils.verify_password_v4(
user_password, u_value, o_value, permissions, file_id, key_length, revision
)
assert verified_key == encryption_key
ciphertext = EncryptionUtils.encrypt_aes_cbc(verified_key, b"Confidential PDF content")
decrypted = EncryptionUtils.decrypt_aes_cbc(verified_key, ciphertext)
assert decrypted == b"Confidential PDF content"o_value en u_value zijn altijd 32 bytes, ongeacht key_length. verify_password_v4 retourneert None — geen uitzondering — wanneer het wachtwoord niet overeenkomt.
Stap 5: AES-256-sleutels afleiden voor revisie 5/6-documenten
Beveiligingshandlers voor revisie 5 en 6 (AES-256) gebruiken geen compute_owner_key_v4/compute_user_key_v4 — ze hashen het wachtwoord met compute_hash_v5, die ISO 32000-2’s “Algorithm 2.B” implementeert. Gebruik generate_file_id voor een nieuwe bestandsidentificatie, en derive_object_key om een bestandsversleutelingssleutel om te zetten in een sleutel voor één specifiek indirect object.
password = b"SecurePassword123"
salt = os.urandom(8)
password_hash = EncryptionUtils.compute_hash_v5(password, salt)
assert len(password_hash) == 32
file_id = EncryptionUtils.generate_file_id()
assert len(file_id) == 16
file_key = os.urandom(32)
object_key = EncryptionUtils.derive_object_key(file_key, 12, 0, use_aes=True)
assert len(object_key) == 16derive_object_key mixt het objectnummer en het generatie-nummer in de bestands-sleutel, zodat elk indirect object zijn eigen sleutel krijgt, hoewel de bestands-sleutel wordt gedeeld.
Veelvoorkomende problemen en oplossingen
encrypt_aes_cbc/decrypt_aes_cbc geeft de fout “AES key must be 16, 24, or 32 bytes”. Het key-argument moet een echte AES-sleutel zijn, geen ruwe wachtwoord-string. Genereer er één met os.urandom(16 | 24 | 32), of leid er eerst een af met compute_user_key_v4 (Revisies 2-4) of compute_hash_v5 (Revisies 5/6).
verify_password_v4 returns None in plaats van te gooien. Dit betekent dat het wachtwoord niet overeenkomt — het is geen foutconditie om af te vangen, maar een resultaat om te controleren. Controleer ook dat permissions, file_id, key_length, en revision zijn exact dezelfde waarden die werden gebruikt toen de document’s o_value and u_value oorspronkelijk werden berekend; een mismatch in een van hen produceert stilletjes de verkeerde sleutel in plaats van luidruchtig te falen.
compute_owner_key_v4 met een leeg eigenaarwachtwoord. Passing "" for owner_password is volgens de specificatie gedefinieerd gedrag, geen bug — het algoritme valt terug op het gebruik van het gebruikerswachtwoord, waardoor het eigenaar- en gebruikerswachtwoord gelijk worden.
Sleutels afgeleid voor de verkeerde revisie of sleutellengte. Revisie 2 gebruikt 40-bit (5-byte) RC4-sleutels, Revisie 3/4 gebruiken 128-bit (16-byte) RC4/AES-sleutels, en Revisie 5/6 gebruiken compute_hash_v5 in plaats van compute_owner_key_v4/compute_user_key_v4 volledig. Het mengen hiervan veroorzaakt geen uitzondering — het produceert alleen een sleutel die het document niet kan openen.
compute_hash_v5 output verandert onverwacht. Het derde argument (user_key) wordt gemixt in de hash. Geef b"" expliciet wanneer je een eenvoudige wachtwoordvalidatiehash wilt, aangezien het weglaten ervan niet hetzelfde is als het doorgeven van een lege waarde op elke aanroepplaats.
Veelgestelde vragen
Waarom is EncryptionUtils niet rechtstreeks importeerbaar vanuit aspose_pdf?
Het bevindt zich in de engine subpackage omdat het een interne implementatiedetail is van document-niveau wachtwoordbescherming, en geen onderdeel van de high-level publieke API interface. Importeer het expliciet vanuit aspose_pdf.engine.encryption.
Is compute_hash_v5 hetzelfde als één enkele SHA-256 aanroep?
Nee. Het implementeert Algoritme 2.B van ISO 32000-2, dat meerdere rondes uitvoert met verschillende hash-algoritmen die worden geselecteerd op basis van tussenliggende waarden — opzettelijk duurder dan één enkele hash-aanroep.
Geeft generate_file_id() elke keer dezelfde bytes terug?
Nee — het retourneert bij elke oproep een verse, willekeurige 16-byte waarde. Een andere bestands-identifier verandert elke sleutel die ervan wordt afgeleid, zelfs wanneer het wachtwoord identiek is.
Delen alle indirecte objecten in een versleutelde PDF één sleutel?
Nee. derive_object_key combineert het objectnummer en het generatie-nummer met de bestands-encryptiesleutel, zodat elk indirect object een eigen per-object sleutel krijgt.
Moet applicatiecode EncryptionUtils direct aanroepen om een PDF met een wachtwoord te beveiligen?
Meestal niet. EncryptionUtils is de low-level engine waarop de document-niveau wachtwoord-API’s zijn gebouwd. De meeste applicaties zouden PDF’s moeten beveiligen via de document-niveau API en alleen EncryptionUtils moeten aanspreken voor aangepaste tooling of forensisch onderzoek van versleutelde bestanden.