نحوه کار با موتور رمزگذاری PDF در Python
Aspose.PDF FOSS برای Python (import aspose_pdf) حفاظت از رمز عبور PDF را در سطح بایت از طریق یک کلاس موتور داخلی کوچک به نام EncryptionUtils در aspose_pdf.engine.encryption پیادهسازی میکند. اینجا جایی است که رمز AES-CBC و الگوریتمهای استخراج کلید هندلر امنیتی استاندارد PDF (ISO 32000 نسخههای ۲ تا ۶) واقعاً قرار دارند، مستقل از Document سطح بالا API. این راهنما بسته را نصب میکند و سه کار موتور را مرور مینماید: رمزگذاری و رمزگشایی بایتهای خام با AES-CBC، استخراج کلیدهای هندلر امنیتی استاندارد برای یک رمز عبور (نسخههای ۲-۴)، و استخراج کلیدهای AES-256 برای اسناد نسخه ۵/۶.
راهنمای گام به گام
گام ۲: وارد کردن کلاسهای مورد نیاز
EncryptionUtils از بسته سطح-بالای aspose_pdf دوباره صادر نمیشود — آن را مستقیماً از زیربخش engine.encryption وارد کنید:
import os
from aspose_pdf.engine.encryption import EncryptionUtilsگام ۳: رمزگذاری و رمزگشایی دادهها با AES-CBC
encrypt_aes_cbc و decrypt_aes_cbc مستقیماً بر روی هر کلید ۱۶، ۲۴ یا ۳۲ بایتی (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 همیشه ۳۲ بایت هستند بدون در نظر گرفتن 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 هش میکنند، که الگوریتم 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 باید ۱۶، ۲۴ یا ۳۲ بایت باشد”. آرگومان کلید باید یک کلید واقعی AES باشد، نه یک رشتهٔ رمز عبور خام. یک کلید تولید کنید با os.urandom(16 | 24 | 32)، یا ابتدا یکی را استخراج کنید با compute_user_key_v4 (نسخههای ۲-۴) یا compute_hash_v5 (نسخههای ۵/۶).
verify_password_v4 returns None به جای پرتاب خطا. این به این معنی است که رمز عبور مطابقت نداشت — این یک وضعیت خطا برای گرفتن نیست، فقط نتیجهای برای بررسی است. همچنین تأیید کنید که permissions, file_id, key_length، و revision دقیقاً همان مقادیر هستند که هنگام محاسبهٔ سند استفاده شدهاند o_value and u_value در ابتدا محاسبه شدند؛ عدم تطابق در هر یک از آنها بهصورت ساکت کلید اشتباه تولید میکند بهجای اینکه بهصراحت خطا بدهد.
compute_owner_key_v4 با رمز عبور صاحب خالی. Passing "" for owner_password رفتاری تعریفشده توسط مشخصات است، نه یک باگ — الگوریتم بهکارگیری رمز عبور کاربر را بهعنوان پیشفرض انتخاب میکند، بنابراین رمزهای عبور صاحب و کاربر معادل میشوند.
کلیدهایی که برای نسخه یا طول کلید نادرست مشتق شدهاند. نسخهٔ ۲ از کلیدهای RC4 ۴۰ بیتی (۵ بایتی) استفاده میکند، نسخهٔ ۳/۴ از کلیدهای RC4/AES ۱۲۸ بیتی (۱۶ بایتی) استفاده میکنند، و نسخهٔ ۵/۶ از compute_hash_v5 بهجای compute_owner_key_v4/compute_user_key_v4 بهطور کامل. ترکیب اینها استثنایی تولید نمیکند — فقط کلیدی تولید میشود که قادر به باز کردن سند نخواهد بود.
compute_hash_v5 خروجی بهطور ناگهانی تغییر میکند. آرگومان سوم (user_key) در هش ترکیب میشود. ارسال کنید b"" بهصورت صریح وقتی میخواهید یک هش سادهٔ اعتبارسنجی رمز عبور داشته باشید، زیرا حذف آن با ارسال مقدار خالی در هر محل فراخوانی یکسان نیست.
سوالات متداول
چرا EncryptionUtils بهصورت مستقیم از aspose_pdf قابل وارد کردن نیست؟
این در زیرپکیج engine قرار دارد زیرا جزئیات پیادهسازی داخلی محافظت رمز عبور در سطح سند است و بخشی از سطح عمومی سطح بالا API نیست. آن را بهصورت صریح از aspose_pdf.engine.encryption وارد کنید.
آیا compute_hash_v5 همانند یک فراخوانی SHA-256 واحد است؟
خیر. این پیادهسازی الگوریتم ۲.ب استاندارد ISO 32000-2 است که چندین دور را با استفاده از الگوریتمهای هش مختلف که توسط مقادیر میانی انتخاب میشوند، انجام میدهد — عمداً گرانتر از یک فراخوانی هش واحد.
آیا generate_file_id() هر بار همان بایتها را برمیگرداند؟
خیر — هر بار مقدار تازه و تصادفی ۱۶ بایتی را برمیگرداند. شناسهٔ فایل متفاوت، تمام کلیدهای مشتقشده از آن را تغییر میدهد، حتی اگر رمز عبور یکسان باشد.
آیا تمام اشیاء غیرمستقیم در یک PDF رمزگذاریشده یک کلید مشترک دارند؟
خیر. derive_object_key شمارهٔ شیء و شمارهٔ نسل را با کلید رمزگذاری فایل ترکیب میکند، بنابراین هر شیء غیرمستقیم یک کلید متمایز مخصوص به خود دریافت میکند.
آیا کد برنامه باید بهصورت مستقیم EncryptionUtils را برای حفاظت با رمز عبور یک PDF فراخوانی کند؟
معمولاً نه. EncryptionUtils موتور سطح پایین است که APIهای رمز عبور در سطح سند بر پایهٔ آن ساخته شدهاند. اکثر برنامهها باید PDFها را از طریق API در سطح سند محافظت کنند و فقط برای ابزارهای سفارشی یا بازرسی قضایی فایلهای رمزگذاریشده از EncryptionUtils استفاده کنند.