تخطَّ إلى المحتوى

تشفير ملف PDF باستخدام AES-256 وضبط الأذونات

استخدم هذه الوصفة لتشفير مستند باستخدام ⁨AES-256.⁩ ستعيّن كلمة مرور للمستخدم، وكلمة مرور للمالك، وقناع بتات للأذونات يقيّد العمليات المسموح بها. تتبع الوصفة examples/22-protection.php.

قابلية إعادة الإنتاج — لماذا تُعدّ هذه الوصفة structural، لا bitwise. إنّ ملف ⁨PDF⁩ مشفّر بـ ⁨AES-256⁩ لا يتطابق مطلقًا على مستوى البايت بين عمليات التشغيل، حتى مع الإدخال نفسه وكلمات المرور نفسها. قبل اشتقاق مفتاح تشفير الملف، يولّد معالج الأمان القياسي في المراجعة 6 16 بايت عشوائية جديدة (أملاح التحقق من ⁨user/owner⁩ وأملاح المفتاح) لكل عملية تشفير باستخدام مولّد أرقام عشوائية قوي ‏(⁨ISO 32000-2⁩ §7.6.4، الخوارزمية 2.⁨B⁩). يستخدم ⁨AES-256-CBC⁩ متجه تهيئة عشوائيًا لكل كائن. كذلك، يكون المُذيَّل /ID مصفوفة من سلسلتي بايت. عنصره الأول مُعرّف دائم مُشتق من الملف وقت إنشائه (⁨ISO 32000-2⁩ §14.4). لذلك يكون ملف قابلية إعادة الإنتاج structural: قبل أن يقارن بين عمليتي تشغيل، يوحّد إطار الاختبار أملاح التشفير/متجه التهيئة، وترتيب الكائنات، و ‏/ID المُذيَّل، بدلًا من التحقق من تطابق بايتي مستحيل.

  • تثبيت ⁨Core⁩‏: composer require nextpdf/core:^3.
  • امتداد ⁨PHP⁩ باسم openssl، الذي يتطلبه مُشفّر ⁨AES-256.⁩
  1. أنشئ المستند.
  2. استدعِ setEncryption() قبل addPage(). يجب أن يكون المُشفّر جاهزًا قبل كتابة أي كائن محتوى.
  3. مرّر كلمة مرور للمستخدم (مطلوبة لفتح المستند)، وكلمة مرور للمالك (للوصول الكامل)، وقناع بتات للأذونات.
  4. أضف المحتوى، ثم احفظ. يشفّر الكاتب محتوى كل كائن.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Permission bits (ISO 32000-2, encryption dictionary P entry):
// bit 3 (4) allow printing
// bit 4 (8) allow content modification
// bit 5 (16) allow text extraction / copying
// bit 6 (32) allow annotation and form editing
// Grant printing only:
$permissions = 4;
$doc = Document::createStandalone();
$doc->setTitle('Encrypted Document');
// setEncryption() MUST run before addPage(). Order matters.
$doc->setEncryption(
userPassword: 'open-me',
ownerPassword: 'owner-secret',
permissions: $permissions,
);
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'This document is encrypted with AES-256.', newLine: true);
$doc->save(__DIR__ . '/encrypted.pdf');
echo "Wrote encrypted.pdf (AES-256, printing only)\n";
Wrote encrypted.pdf (AES-256, printing only)

عند فتح encrypted.pdf، يطلب القارئ كلمة مرور. تفتح كلمة مرور المستخدم المستند وفق مجموعة الأذونات المقيّدة، بينما تفتحه كلمة مرور المالك بوصول كامل.

  • ترتيب الاستدعاء. استدعاء setEncryption() بعد addPage() لا يشفّر المحتوى السابق بأثر رجعي. اضبط التشفير دائمًا أولًا.
  • القيمة الافتراضية لكلمة مرور المالك. عندما تكون كلمة مرور المالك فارغة، يعيد المحرك استخدام كلمة مرور المستخدم ككلمة مرور للمالك. عيّن كلمتي مرور مختلفتين عندما يجب الفصل بين هذين الدورين.
  • دلالات الأذونات — القيد. تحترم القارئات المتوافقة بتات الأذونات، لكنها لا تُفرض تشفيريًا: يمكن لقارئ يتجاهل البتات، أو لأداة تُستخدم مع كلمة مرور المالك، أن ينفّذ العمليات المقيّدة. تعامل مع الأذونات بوصفها إشارة سياسة للبرامج المتعاونة، لا بوصفها تحكمًا في الوصول يصمد أمام طرف عازم.
  • تعارض ⁨PDF/A.⁩ يحظر ⁨PDF/A⁩ مفتاح المُذيَّل Encrypt. استدعاء setEncryption() على مستند ⁨PDF/A⁩، أيًا كان ترتيب الاستدعاء، يطرح استثناء عدم توافق. راجع بوابة التوافق ⁨PDF/A-4⁩.
  • ⁨AES-256-GCM.⁩ يفعّل useAesGcm() تشفير ⁨GCM⁩ المجمّع وفق ⁨ISO/TS 32003⁩ عندما يوفّر المضيف الشيفرة عبر ⁨OpenSSL⁩ أو ⁨libsodium⁩. وإلا، فإنه يطرح InvalidConfigException.
العبارةالمواصفةالبند⁨reference_id⁩
يحدّد معالج الأمان القياسي خوارزمية التشفير وطول المفتاح.⁨ISO 32000-2⁩§7.6
يحمل مُدخل P في قاموس التشفير بتات الأذونات.⁨ISO 32000-2⁩§7.6

يحمي التشفير سرية المحتوى من الأطراف التي لا تملك كلمة المرور. أما بتات الأذونات فهي إرشادية للقارئات، ولا تمنع وحدها أداة غير متوافقة من التصرف.