Cara Bekerja dengan Mesin Enkripsi PDF di Python

Cara Bekerja dengan Mesin Enkripsi PDF di Python

Aspose.PDF FOSS untuk Python (import aspose_pdf) mengimplementasikan perlindungan kata sandi PDF pada tingkat byte melalui kelas mesin internal kecil, EncryptionUtils, di aspose_pdf.engine.encryption. Di sinilah cipher AES-CBC dan algoritma derivasi kunci PDF Standard Security Handler (ISO 32000 Revisi 2 hingga 6) berada, terlepas dari Document API tingkat tinggi. Panduan ini menginstal paket dan menjelaskan tiga tugas mesin: mengenkripsi dan mendekripsi byte mentah dengan AES-CBC, menghasilkan kunci Standard Security Handler untuk sebuah kata sandi (Revisi 2-4), dan menghasilkan kunci AES-256 untuk dokumen Revisi 5/6.

Panduan Langkah-demi-Langkah

Langkah 2: Impor Kelas yang Diperlukan

EncryptionUtils tidak diekspor kembali dari paket aspose_pdf tingkat atas — impor langsung dari submodul engine.encryption:

import os
from aspose_pdf.engine.encryption import EncryptionUtils

Langkah 3: Enkripsi dan Dekripsi Data dengan AES-CBC

encrypt_aes_cbc dan decrypt_aes_cbc bekerja langsung pada kunci 16-, 24-, atau 32-byte apa pun (AES-128, AES-192, atau AES-256) tanpa melalui derivasi kunci berbasis kata sandi. encrypt_aes_cbc menerapkan padding PKCS7 secara internal, dan decrypt_aes_cbc menghapusnya.

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))

Langkah 4: Turunkan Kunci Penangan Keamanan Standar untuk Kata Sandi (Revisi 2-4)

compute_owner_key_v4 menghitung nilai kata sandi Pemilik (O) menurut Algoritma 3.3, dan compute_user_key_v4 menghitung nilai kata sandi Pengguna (U) serta kunci enkripsi berkas menurut Algoritma 3.4/3.5. verify_password_v4 menurunkan kembali kunci dari kata sandi kandidat sehingga Anda dapat memastikan bahwa ia membuka dokumen sebelum mempercayainya.

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 dan u_value selalu berukuran 32 byte terlepas dari key_length. verify_password_v4 mengembalikan None — bukan pengecualian — ketika kata sandi tidak cocok.


Langkah 5: Turunkan Kunci AES-256 untuk Dokumen Revisi 5/6

Penangan keamanan revisi 5 dan 6 (AES-256) tidak menggunakan compute_owner_key_v4/compute_user_key_v4 — mereka melakukan hash pada kata sandi dengan compute_hash_v5, yang mengimplementasikan “Algorithm 2.B” ISO 32000-2. Gunakan generate_file_id untuk identifier berkas baru, dan derive_object_key untuk mengubah kunci enkripsi berkas menjadi kunci bagi satu objek tidak langsung tertentu.

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) == 16

derive_object_key mencampur nomor objek dan nomor generasi ke dalam kunci berkas, sehingga setiap objek tidak langsung mendapatkan kuncinya masing-masing meskipun kunci berkas dibagi.


Masalah Umum dan Solusinya

encrypt_aes_cbc/decrypt_aes_cbc menimbulkan “AES key must be 16, 24, or 32 bytes”. Argumen kunci harus berupa kunci AES yang sebenarnya, bukan string kata sandi mentah. Hasilkan satu dengan os.urandom(16 | 24 | 32), atau turunkan satu terlebih dahulu dengan compute_user_key_v4 (Revisi 2-4) atau compute_hash_v5 (Revisi 5/6).

verify_password_v4 returns None alih-alih menimbulkan. Ini berarti kata sandi tidak cocok — ini bukan kondisi error yang harus ditangkap, melainkan hasil yang harus diperiksa. Juga pastikan bahwa permissions, file_id, key_length, dan revision adalah nilai yang persis sama yang digunakan ketika dokumen o_value and u_value dihitung awal; ketidaksesuaian pada salah satu dari mereka secara diam-diam menghasilkan kunci yang salah alih-alih gagal dengan keras.

compute_owner_key_v4 dengan kata sandi pemilik yang kosong. Passing "" for owner_password adalah perilaku yang didefinisikan oleh spesifikasi, bukan bug — algoritma kembali menggunakan kata sandi pengguna, sehingga kata sandi pemilik dan pengguna menjadi setara.

Kunci yang dihasilkan untuk revisi atau panjang kunci yang salah. Revisi 2 menggunakan kunci RC4 40-bit (5-byte), Revisi 3/4 menggunakan kunci RC4/AES 128-bit (16-byte), dan Revisi 5/6 menggunakan compute_hash_v5 alih-alih compute_owner_key_v4/compute_user_key_v4 sepenuhnya. Mencampur ini tidak memunculkan pengecualian — itu hanya menghasilkan kunci yang tidak dapat membuka dokumen.

compute_hash_v5 output berubah secara tak terduga. Argumen ketiga (user_key) dicampur ke dalam hash. Berikan b"" secara eksplisit ketika Anda menginginkan hash password-validation biasa, karena menghilangkannya tidak sama dengan memberikan nilai kosong di setiap lokasi pemanggilan.


Pertanyaan yang Sering Diajukan

Mengapa EncryptionUtils tidak dapat diimpor langsung dari aspose_pdf?

Ia berada di subpaket engine karena merupakan detail implementasi internal dari perlindungan password pada tingkat dokumen, bukan bagian dari antarmuka publik API tingkat tinggi. Impor secara eksplisit dari aspose_pdf.engine.encryption.

Apakah compute_hash_v5 sama dengan satu panggilan SHA-256?

Tidak. Ia mengimplementasikan Algoritma 2.B dari ISO 32000-2, yang melakukan beberapa putaran menggunakan algoritma hash berbeda yang dipilih oleh nilai menengah — sengaja lebih mahal daripada satu panggilan hash.

Apakah generate_file_id() mengembalikan byte yang sama setiap kali?

Tidak — ia mengembalikan nilai 16-byte acak baru pada setiap panggilan. Identifikasi file yang berbeda mengubah setiap kunci yang dihasilkan darinya, bahkan ketika kata sandi identik.

Apakah semua objek tidak langsung dalam PDF terenkripsi berbagi satu kunci?

Tidak. derive_object_key menggabungkan nomor objek dan nomor generasi dengan kunci enkripsi file, sehingga setiap objek tidak langsung mendapatkan kunci per-objek yang berbeda.

Haruskah kode aplikasi memanggil EncryptionUtils secara langsung untuk melindungi PDF dengan kata sandi?

Biasanya tidak. EncryptionUtils adalah mesin tingkat rendah yang menjadi dasar API kata sandi tingkat dokumen. Kebanyakan aplikasi harus melindungi PDF melalui API tingkat dokumen dan hanya menggunakan EncryptionUtils untuk alat khusus atau inspeksi forensik file terenkripsi.


Lihat Juga

 Bahasa Indonesia