THotPDF.SignPDFWithPFX

THotPDF

 

السابق  الطرق  AddPubKeyRecipient

يوقّع عنصرًا نائبًا موجودًا في PDF باستخدام ملف PFX / PKCS#12، ويختار هوية اعتماد واحدة بشكل حتمي، ويبني حاوية CMS SignedData بسلسلة الشهادات المتاحة لها، ويكتب ملف PDF الموقَّع في استدعاء واحد

 

بنية Delphi (تحميل زائد للملف):

class function SignPDFWithPFX(

  const InputPDFPath: string;

  const OutputPDFPath: string;

  const PFXFilePath: string;

  const Password: AnsiString): boolean; overload; static;

 

بنية Delphi (تحميل زائد للتدفق):

class function SignPDFWithPFX(

  InputStream: TStream;

  OutputStream: TStream;

  const PFXFilePath: string;

  const Password: AnsiString): boolean; overload; static;

 

الوصف

SignPDFWithPFX هي نقطة الدخول الشاملة لتوقيع PFX من طرف إلى طرف، أُضيفت في الإصدار v2.119.27. يجب أن يحتوي ملف PDF المُدخَل مسبقًا على عنصر نائب للتوقيع أصدَره THPDFPage.AddSignedSignatureField (أو غلافه لـ PAdES) بحقل subFilter بقيمة adbe.pkcs7.detached. تقوم هذه الطريقة بما يلي:

 

1. ينسخ الإدخال عبر مخزن مؤقت محدود بحجم 256 كيلوبايت، أو يعيد استخدام التدفق نفسه القابل للسعي للقراءة والكتابة، ويحدد موضعي العنصرين النائبين /ByteRange و/Contents، ويُصحح عبر السعي حقل /ByteRange ثابت العرض بإزاحات البايت الفعلية

2. يحمّل ملف PFX ويفكّ تشفيره بكلمة المرور المزوَّدة. يقبل PBES2 خوارزميات AES-128-CBC وAES-192-CBC وAES-256-CBC مع دوال PBKDF2 العشوائية الزائفة الافتراضية HMAC-SHA-1 أو الصريحة HMAC-SHA-256 وHMAC-SHA-384 وHMAC-SHA-512. يجب أن يطابق طول المفتاح الاختياري لـ PBKDF2، أي keyLength، خوارزمية AES المختارة، وتبقى ملفات PBE-SHA1-3DES القديمة مدعومة لتصديرات الشهادات الأقدم. أما ملفات التشفير الأخرى فتُثير تشخيصًا يذكر معرّف OID المخالف

3. يقرن المفاتيح الخاصة من نوع RSA أو ECDSA بمنحنى مسمّى أو Ed25519 أو Ed448 بالشهادات عبر مادة المفتاح العام وقيم localKeyId المطابقة تمامًا لمواصفة RFC 2985، ثم يتبع أسماء المُصدِر/الخاضع وامتدادي معرّف مفتاح السلطة/معرّف مفتاح الخاضع للحفاظ على السلسلة الوسيطة والجذر المتاحين

4. يختار مخطط التوقيع من المفتاح المطابق، ويحسب بصمة (digest) المستند المطلوبة، ويبني كتلة DER من نوع CMS SignedData (RFC 5652) تحتوي شهادة الموقِّع وسلسلتها المطابقة دون تكرار شهادات DER، والسمات الموقَّعة. يوقّع RSA وECDSA بصمة السمات؛ بينما يوقّع Ed25519 وEd448 مجموعة سمات DER الكاملة SET OF في وضع PureEdDSA. يستخدم Ed25519 خوارزمية SHA-512 بينما يستخدم Ed448 خوارزمية SHAKE256 بناتج 512 بت مع id-shake256-len

5. يرمّز DER الخاص بـ CMS بترميز سداسي عشري، ويتحقق من أنه يناسب ميزانية /Contents التي حجزها AddSignedSignatureField (تغطي 8 كيلوبايت الافتراضية مفاتيح RSA بطول 1024 / 2048 بت)، ويحقنه في العنصر النائب

6. يكتب البايتات المصحَّحة إلى مسار الإخراج أو التدفق

 

يُعيد True عند النجاح. يُثير EHPDFPFXError عند كلمة مرور خاطئة، أو معماري تشفير أو مفتاح خاص غير مدعوم، أو ملف PFX تالف الصيغة، أو هوية غامضة، أو مُصدِر غامض، أو حلقة في سلسلة الشهادات؛ ويُثير EHPDFCMSError عندما يفتقر ملف PDF المُدخَل إلى العنصر النائب المتوقَّع، أو يكون مزوّد EdDSA الاختياري غير متاح، أو يفشل التوقيع، أو يتجاوز DER الخاص بـ CMS ميزانية /Contents المحجوزة؛ ويُثير EHPDFRSAError عند عدم تطابق مفتاح RSA

 

سير عمل نموذجي

 

Doc := THotPDF.Create(nil);

Doc.FileName := 'unsigned.pdf';

Doc.BeginDoc;

Doc.CurrentPage.AddSignedSignatureField(

  'Sig1', Rect(60, 60, 260, 90), 8192,

  'adbe.pkcs7.detached', 'Approved', 'Brussels', '', []);

Doc.EndDoc;

Doc.Free;

THotPDF.SignPDFWithPFX('unsigned.pdf', 'signed.pdf', 'mykey.pfx', 'mypassword');

 

ملفات PFX متعددة الهويات

يرفض التحميل الزائد الميسَّر عمدًا أي ملف PFX يحتوي أكثر من شهادة ومفتاح خاص مطابقَين. استدعِ HPDFEnumeratePFXIdentities لفحص قائمة الهويات الحتمية وحقليها LocalKeyID وFriendlyName، أو استدعِ HPDFParsePFXByLocalKeyID عندما يلزم مادة المفتاح المحددة فقط

للتوقيع من البداية إلى النهاية، هيّئ THPDFCMSSignOptions عبر HPDFCMSDefaultSignOptions، وانسخ الثمانيات (octets) الدقيقة المحددة إلى Options.PFXLocalKeyID، واستدعِ نسخة HPDFCMSSignPDFStream التي تقبل هذه الخيارات. تُضمَّن الشهادة الطرفية المحددة والشهادات الوسيطة المتاحة والجذر المتاح تلقائيًا؛ وتُدمج قيم Options.AdditionalCertsDER التي يقدمها المستدعي مع إزالة تكرار DER دقيقة

 

ملاحظات

يستخدم توقيع PFX بخوارزميتَي RSA وECDSA مسارات التشفير الأصلية لـ HotPDF وWindows. أما توقيع PFX بخوارزميتَي Ed25519 وEd448 فيتطلب libcrypto من OpenSSL 3؛ ويمكن لمستدعي HPDFCMSSignPDFStream المباشرين ضبط THPDFCMSSignOptions.OpenSSLLibraryPath، بينما يستخدم التحميل الزائد الميسَّر مسار بحث مكتبات المنصة المعتاد

خوارزمية التوقيع هي RSA + SHA-256 (1.2.840.113549.1.1.1 + 2.16.840.1.101.3.4.2.1). ومعرّف الموقِّع هو IssuerAndSerialNumber المستخرَج من شهادة X.509. أما encapContentInfo فمنفصل (detached) (يُحذف eContent). وتُرتَّب السمات الموقَّعة تصاعديًا حسب سلسلة بايتات DER وفق الفقرة 5.4 من RFC 5652 قبل تجزئتها

 

بالنسبة لسير عمل PAdES B-T / B-LT / B-LTA الذي يحتاج طوابع زمنية RFC 3161، أو قواميس DSS، أو توقيعات طابع زمني على المستند، تبقى أدوات جانب المُنتِج (AddPAdESSignatureField, AddPAdESDSSCertificate, AddDocumentTimestampSignature) سارية؛ أما SignPDFWithPFX نفسها فتُصدر توقيعًا أساسيًا من نوع CMS فقط (معادلًا لـ PAdES-B-B)

لا يحتفظ التحميل الزائد للتدفق أبدًا بنسخة كاملة ثانية من PDF في الذاكرة. فهو يُجزّئ المخرجات المصحَّحة على نطاقات محدودة، ويُصحح القيمة السداسية العشرية لـ CMS عبر السعي دون تغيير طول الملف. وتدعم الإزاحات العشرية ثابتة العرض ملفات PDF المُعدَّة الأصغر من 10,000,000,000 بايت

 

انظر أيضًا: AddSignedSignatureField, PreparePDFForSigning, InsertSignatureHex, AddPAdESSignatureField