วิธีทำงานกับเอนจิ้นการเข้ารหัส PDF ใน Python
Aspose.PDF FOSS สำหรับ Python (import aspose_pdf) ใช้การป้องกันด้วยรหัสผ่าน PDF ระดับไบต์ผ่านคลาสเอนจินภายในขนาดเล็กที่ชื่อ EncryptionUtils ใน aspose_pdf.engine.encryption. ที่นี่คือที่ตั้งของอัลกอริธึมการเข้ารหัส AES-CBC และอัลกอริธึมการสร้างคีย์ของ PDF Standard Security Handler (ISO 32000 Revision 2 ถึง 6) ทำงานอย่างอิสระจากระดับสูงของ Document API. คู่มือนี้จะติดตั้งแพ็กเกจและอธิบายขั้นตอนงานของเอนจินสามอย่าง: การเข้ารหัสและถอดรหัสไบต์ดิบด้วย AES-CBC, การสร้างคีย์ Standard Security Handler สำหรับรหัสผ่าน (Revision 2-4), และการสร้างคีย์ AES-256 สำหรับเอกสาร Revision 5/6.
คู่มือแบบทีละขั้นตอน
ขั้นตอนที่ 2: นำเข้าคลาสที่จำเป็น
EncryptionUtils ไม่ได้ถูกส่งออกซ้ำจากแพ็กเกจระดับบน aspose_pdf — ให้นำเข้ามาโดยตรงจากซับโมดูล engine.encryption:
import os
from aspose_pdf.engine.encryption import EncryptionUtilsขั้นตอนที่ 3: เข้ารหัสและถอดรหัสข้อมูลด้วย AES-CBC
encrypt_aes_cbc และ decrypt_aes_cbc ทำงานโดยตรงกับคีย์ขนาด 16, 24 หรือ 32 ไบต์ใดก็ได้ (AES-128, AES-192 หรือ AES-256) โดยไม่ต้องผ่านการสร้างคีย์จากรหัสผ่าน. encrypt_aes_cbc ใช้การเติม PKCS7 ภายใน, และ decrypt_aes_cbc จะลบการเติมนั้นออก.
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))ขั้นตอนที่ 4: สร้างคีย์ตัวจัดการความปลอดภัยมาตรฐานสำหรับรหัสผ่าน (เวอร์ชัน 2-4)
compute_owner_key_v4 คำนวณค่ารหัสผ่านเจ้าของ (O) ตามอัลกอริทึม 3.3, และ compute_user_key_v4 คำนวณค่ารหัสผ่านผู้ใช้ (U) และคีย์การเข้ารหัสไฟล์ตามอัลกอริทึม 3.4/3.5. verify_password_v4 สร้างคีย์ใหม่จากรหัสผ่านที่เป็นตัวเลือกเพื่อให้คุณยืนยันว่าเปิดเอกสารได้ก่อนที่จะเชื่อถือมัน.
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 และ u_value มีขนาดเสมอ 32 ไบต์โดยไม่คำนึงถึง key_length. verify_password_v4 คืนค่า None — ไม่ใช่ข้อยกเว้น — เมื่อรหัสผ่านไม่ตรงกัน.
ขั้นตอนที่ 5: สร้างคีย์ AES-256 สำหรับเอกสารรุ่น 5/6
ตัวจัดการความปลอดภัยรุ่น 5 และ 6 (AES-256) ไม่ใช้ compute_owner_key_v4/compute_user_key_v4 — พวกเขาใช้แฮชรหัสผ่านด้วย compute_hash_v5, ซึ่งเป็นการดำเนินการตาม “Algorithm 2.B” ของ ISO 32000-2. ใช้ generate_file_id สำหรับตัวระบุไฟล์ใหม่, และ derive_object_key เพื่อแปลงคีย์การเข้ารหัสไฟล์ให้เป็นคีย์สำหรับวัตถุอ้อมหนึ่งเฉพาะ.
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 ผสมหมายเลขวัตถุและหมายเลขรุ่นเข้ากับคีย์ไฟล์, ดังนั้นวัตถุอ้อมแต่ละอันจึงได้คีย์ของตนเองแม้ว่าคีย์ไฟล์จะถูกแชร์กัน.
ปัญหาทั่วไปและวิธีแก้ไข
encrypt_aes_cbc/decrypt_aes_cbc ทำให้เกิดข้อผิดพลาด “AES key must be 16, 24, or 32 bytes”. อาร์กิวเมนต์คีย์ต้องเป็นคีย์ AES ที่แท้จริง ไม่ใช่สตริงรหัสผ่านดิบ ให้สร้างคีย์โดยใช้ os.urandom(16 | 24 | 32), หรือสร้างหนึ่งก่อนด้วย compute_user_key_v4 (Revisions 2-4) หรือ compute_hash_v5 (การแก้ไข 5/6).
verify_password_v4 returns None แทนการทำให้เกิดข้อผิดพลาด. นี่หมายความว่ารหัสผ่านไม่ตรงกัน — ไม่ใช่เงื่อนไขข้อผิดพลาดที่ต้องจับ เพียงผลลัพธ์ที่ต้องตรวจสอบเท่านั้น นอกจากนี้ให้ยืนยันว่า permissions, file_id, key_length, และ revision เป็นค่าที่เหมือนกันอย่างแน่นอนที่ใช้เมื่อเอกสาร’s o_value and u_value ถูกคำนวณขึ้นมาเดิม; ความไม่ตรงกันในหนึ่งค่าใดค่าหนึ่งจะสร้างคีย์ที่ผิดโดยเงียบๆ แทนที่จะล้มเหลวอย่างชัดเจน.
compute_owner_key_v4 โดยไม่มีรหัสผ่านเจ้าของ. Passing "" for owner_password เป็นพฤติกรรมที่กำหนดตามสเปค ไม่ใช่บัก — อัลกอริธึมจะย้อนกลับไปใช้รหัสผ่านผู้ใช้ ดังนั้นรหัสผ่านเจ้าของและผู้ใช้จึงกลายเป็นเทียบเท่ากัน.
คีย์ที่ได้จากรุ่นหรือความยาวคีย์ที่ไม่ถูกต้อง. รุ่น 2 ใช้คีย์ RC4 40-bit (5-byte), รุ่น 3/4 ใช้คีย์ RC4/AES 128-bit (16-byte), และรุ่น 5/6 ใช้ compute_hash_v5 แทน compute_owner_key_v4/compute_user_key_v4 โดยสิ้นเชิง การผสมผสานเหล่านี้จะไม่ทำให้เกิดข้อยกเว้น — แต่จะสร้างคีย์ที่ไม่สามารถเปิดเอกสารได้.
compute_hash_v5 ผลลัพธ์เปลี่ยนแปลงโดยไม่คาดคิด. อาร์กิวเมนต์ที่สาม (user_key) ถูกผสมเข้าไปในแฮช ส่ง b"" อย่างชัดเจนเมื่อคุณต้องการแฮชการตรวจสอบรหัสผ่านแบบธรรมดา เนื่องจากการละเว้นไม่ได้เท่ากับการส่งค่าที่ว่างเปล่าในทุกจุดเรียกใช้.
คำถามที่พบบ่อย
ทำไม EncryptionUtils ไม่สามารถนำเข้าได้โดยตรงจาก aspose_pdf?
มันอยู่ใน subpackage engine เนื่องจากเป็นรายละเอียดการทำงานภายในของการป้องกันรหัสผ่านระดับเอกสาร ไม่ได้เป็นส่วนของ API สาธารณะระดับสูง จึงต้องนำเข้ามาอย่างชัดเจนจาก aspose_pdf.engine.encryption.
compute_hash_v5 เป็นเช่นเดียวกับการเรียก SHA-256 เพียงครั้งเดียวหรือไม่?
ไม่. มันใช้ Algorithm 2.B ของ ISO 32000-2 ซึ่งทำหลายรอบโดยใช้แฮชอัลกอริทึมที่ต่างกันที่เลือกตามค่ากลาง — โดยเจตนาให้มีค่าใช้จ่ายสูงกว่าการเรียกแฮชเพียงครั้งเดียว.
generate_file_id() ส่งคืนไบต์เดียวกันทุกครั้งหรือไม่?
ไม่ — มันส่งค่าที่ใหม่และสุ่มขนาด 16 ไบต์ในแต่ละครั้งที่เรียก. ตัวระบุไฟล์ที่แตกต่างกันจะทำให้คีย์ทุกคีย์ที่ได้จากมันเปลี่ยนแปลง แม้รหัสผ่านจะเหมือนกันก็ตาม.
วัตถุอ้อมทั้งหมดใน PDF ที่เข้ารหัสใช้คีย์เดียวกันหรือไม่?
ไม่. derive_object_key รวมหมายเลขวัตถุและหมายเลขรุ่นเข้ากับคีย์การเข้ารหัสไฟล์ ทำให้วัตถุอ้อมแต่ละอันได้รับคีย์เฉพาะของวัตถุนั้น.
โค้ดแอปพลิเคชันควรเรียก EncryptionUtils โดยตรงเพื่อปกป้อง PDF ด้วยรหัสผ่านหรือไม่?
โดยปกติไม่ใช่. EncryptionUtils เป็นเอนจินระดับต่ำที่ API รหัสผ่านระดับเอกสารสร้างขึ้นจากมัน แอปพลิเคชันส่วนใหญ่ควรปกป้อง PDF ผ่าน API ระดับเอกสารและใช้ EncryptionUtils เฉพาะเมื่อจำเป็นสำหรับเครื่องมือแบบกำหนดเองหรือการตรวจสอบทางนิติวิทยาศาสตร์ของไฟล์ที่เข้ารหัส.