في قطاعات القانون والتمويل والرعاية الصحية، يعد إنشاء كميات كبيرة من مستندات PDF ممارسة قياسية. ومع ذلك، فإن إنتاج المستندات يمثل نصف المعركة فقط؛ فتأمينها لا يقل أهمية. عندما يكون لديك مسار أرشفة يعالج مئات الجيجابايت من ملفات PDF يوميًا، فإن تطبيق تشفير AES-256 يمكن أن يصبح بسرعة عنق زجاجة للأداء.
في هذه المقالة، سنستكشف كيفية تحقيق تشفير AES-256 عالي السرعة لملفات PDF في Delphi من خلال تجنب استنفاد الذاكرة وتحسين حلقات التشفير.
مواصفات تشفير PDF
تطور أمان PDF بشكل كبير. استخدمت الإصدارات المبكرة RC4 بتشفير 40 بت، وهو أمر يسهل اختراقه اليوم. يتطلب المعيار الحالي (PDF 1.7 Extension Level 3 و PDF 2.0) تشفير AES-256.
في ملف PDF، لا تقوم بتشفير كتلة الملف بأكملها. تظل بنية المستند (جدول XRef وبنية القواميس) نصًا عاديًا. بدلاً من ذلك، تقوم بتشفير التيارات (Streams) (البيانات الخام للصور ومحتوى الصفحة) و السلاسل (Strings) (مثل نص البيانات الوصفية). يتطلب هذا من المحلل استخراج البيانات وتطبيق AES CBC وكتابتها مرة أخرى.
عنق الزجاجة: التحميل إلى الذاكرة
من الأخطاء الشائعة عند تشفير ملف PDF ضخم (مثل أرشيف ممسوح ضوئيًا بحجم 2 جيجابايت) تحميل التيار بأكمله في `TMemoryStream` قبل تمريره إلى محرك التشفير. يؤدي هذا إلى استثناءات نفاد الذاكرة (OOM) في عمليات 32 بت وأخطاء صفحات ضخمة (page faulting) في عمليات 64 بت.
تشفير الدفق في Delphi
الحل هو استخدام نهج متدفق ومجزأ. باستخدام واجهة برمجة تطبيقات التشفير في Windows: الجيل التالي (CNG) أو مكتبة مثل OpenSSL، يمكنك قراءة تيار PDF في كتل بحجم 64 كيلوبايت، وتشفير الكتلة، وكتابتها مباشرة إلى تيار قرص الإخراج.
إليك مثال مفاهيمي في Delphi يوضح حلقة تشفير مخزنة مؤقتًا لتيار:
uses
System.Classes, System.SysUtils;
const
BUFFER_SIZE = 65536; // 64KB chunks
// This represents your AES-256 encryption routine
procedure EncryptStreamChunk(const InBuffer; var OutBuffer; BytesRead: Integer; const Key: TBytes; const IV: TBytes);
begin
// Call to Windows CNG (BCryptEncrypt) or OpenSSL (EVP_EncryptUpdate)
// ...
end;
procedure EncryptLargePDFStream(InputStream, OutputStream: TStream; const Key, IV: TBytes);
var
InBuffer, OutBuffer: array of Byte;
BytesRead: Integer;
begin
SetLength(InBuffer, BUFFER_SIZE);
// AES CBC requires padding, so the output buffer must be slightly larger
SetLength(OutBuffer, BUFFER_SIZE + 16);
InputStream.Position := 0;
OutputStream.Position := 0;
repeat
BytesRead := InputStream.Read(InBuffer[0], BUFFER_SIZE);
if BytesRead > 0 then
begin
EncryptStreamChunk(InBuffer[0], OutBuffer[0], BytesRead, Key, IV);
// Write the encrypted cipher text directly to disk
OutputStream.Write(OutBuffer[0], BytesRead); // Note: padding logic omitted for brevity
end;
until BytesRead < BUFFER_SIZE;
end;
تحسين الواجهة الخلفية للتشفير
لدى مطوري Delphi عدة خيارات للواجهة الخلفية لـ AES:
- تطبيقات Delphi الأصلية: سهلة النشر، ولكنها غالبًا ما تكون أبطأ لأنها تعمل بالكامل كبرمجيات.
- Windows CNG (BCrypt): مُحسّن للغاية ويمكنه استخدام تسريع الأجهزة (تعليمات AES-NI على وحدات المعالجة المركزية الحديثة من Intel/AMD).
- OpenSSL (libcrypto): المعيار الصناعي، سريع بشكل لا يصدق، ولكنه يتطلب شحن ملفات DLL خارجية.
بالنسبة لتطبيقات الخوادم ذات الإنتاجية العالية، يعد AES-NI المسرع بالأجهزة أمرًا إلزاميًا. عند استخدام Windows CNG في Delphi، فإن تعيين وظيفة BCryptEncrypt يسمح لتطبيقك بتفريغ المهام الثقيلة إلى السيليكون المشفر المخصص لوحدة المعالجة المركزية، مما يقلل بشكل فعال من نفقات التشفير إلى ما يقرب من الصفر.
الخلاصة
عند تشفير ملفات PDF بحجم الجيجابايت، اعتمد على تجزئة التيار بدلاً من التخزين المؤقت الكامل للذاكرة، وتأكد من أن الواجهة الخلفية للتشفير تستخدم تسريع أجهزة AES-NI. يضمن هذا المزيج تشغيل مسار الأرشيف الخاص بك بسرعة محركات أقراص NVMe، بدلاً من التقيد بوحدة المعالجة المركزية.
ملاحظة: التشفير عالي السرعة AES-256 باستخدام الدفق المجزأ مدعوم محليًا في مكون HotPDF VCL.