مقال تقني

حساب منحنيات NIST بلغة Pascal خالصة لتوقيع PDF

يؤدي HotPDF اتفاق مفاتيح المنحنيات الإهليلجية والتحقق من التواقيع لـ PDF بلغة Object Pascal خالصة، دون ربط بـ OpenSSL ودون مزود تشفير منصات في المسار. ويغطي ذلك خمسة منحنيات: P-256 وP-384 وP-521 لعائلات NIST الأولية، إضافة إلى X25519 وX448 لاتفاق المفاتيح على منحنى Montgomery. وسبب كتابة ذلك الكود بدل ربطه هو النشر لا النقاء. فتطبيق Delphi أو Free Pascal يشحن ملفا تنفيذيا واحدا دون DLL تشفير لا يملك انحراف إصدارات لإدارته، ولا مزودا لكل منصة لاكتشافه، ولا شيئا يتغير سلوكه عندما يرقّع العميل مكتبات نظامه

الكلفة أنك تملك الحساب الآن. الضرب المعياري للأعداد الكبيرة كود لا يسامح: فهو إما ينتج نتائج مطابقة بايتا ببايت للمتجهات الاختبارية المنشورة وإما ينتج خربشة معقولة المظهر، والمسافة بين الحالتين قد تكون مقارنة واحدة. هذه حكاية تلك المقارنة، لأن شكل العيب يتعمم على أي نقل لعمليات المجال إلى Pascal

لماذا تحتاج مكتبة PDF إلى حساب منحنيات أصلا؟

ميزتان تجذبان ذلك. الأولى تشفير المستندات بالمفتاح العام: معالج قائمة المستلمين في ISO 32000 يغلف مفتاحا لكل مستند لشهادات مسماة، وعندما يحمل مستلم مفتاح EC يجري التغليف عبر اتفاق المفاتيح لا نقل مفاتيح RSA. ومن دون ECDH لا سبيل لفتح مثل ذلك المستند. والثانية التحقق من التواقيع. التحقق من توقيع ECDSA على بايتات /ByteRange يحتاج ضرب نقطة على منحنى الموقّع، وP-384 شائع في الملفات الحكومية وملفات التواقيع المؤهلة حيث يعد P-256 الحد الأدنى لا الهدف. ويكشف HotPDF نتائج ذلك العمل عبر مسار التحقق ECDSA وCMS وعبر نموذج مزودي التوقيع القابلين للتوصيل

مخطط مواضع استخدام حساب المنحنيات بلغة Pascal الخالصة في HotPDF: تشفير ECDH لقائمة المستلمين والتحقق من توقيع ECDSA على ByteRange
اتفاق المفاتيح يفتح المستندات المشفرة بـ EC للمستلمين المسماين، بينما يحتاج التحقق من التواقيع ضرب نقطة على منحنى الموقّع

CIOS والطرح الوحيد في النهاية

يتجنب ضرب Montgomery القسمة بالعمل في مجال محوّل يكون فيه التخفيض إزاحة. والصيغة التي يستخدمها HotPDF هي Coarsely Integrated Operand Scanning، التي تدمج الضرب والتخفيض جزءا بجزء كي لا ينمو الوسطى أبدا فوق عرض القاسم مع جزء واحد. وجسم الحلقة مستقيم وسهل الاختبار. أما الذيل فليس كذلك: بعد المرورات المدمجة يمكن للمراكم أن يكون في أي مكان في المدى حتى ضعفي القاسم، فينتهي الخوارزمية بطرح شرطي يزيل نسخة واحدة من العدد الأولي إذا وفقط إذا كان المراكم أكبر منه أو يساويه

مقارنة عددين متعددي الأجزاء تعني السير من الجزء الأعلى أهمية نزولا مع حمل اقتراض. والطريقة البديهية لكتابتها مقارنة جزء المراكم مع جزء القاسم مضافا إليه الاقتراض القادم. تلك الصيغة خاطئة، وهي خاطئة بطريقة يخفيها معظم المنحنيات

// خاطئ: قد يلتف P[I] + Borrow عندما يكون P[I] هو $FFFFFFFFFFFFFFFF
if T[I] < P[I] + Borrow then
begin
  Borrow := 1;
  Break;
end;

// صحيح: قارن من دون إضافة إلى جزء أبدا
if (T[I] < P[I]) or ((T[I] = P[I]) and (Borrow = 1)) then
begin
  Borrow := 1;
  Break;
end;

كيف يبدو التفاف الاقتراض فعلا؟

يبدو كمنحنى يعمل في كل مكان عدا الإنتاج. فالأعداد الأولية لـ P-384 وP-521 تحوي أجزاء مكونة كليا من الواحدات، فيساوي P[I] قيمة $FFFFFFFFFFFFFFFF. أضف إليه الاقتراض القادم الواحد فيلتف عدد غير موقع ذو 64 بت إلى صفر. ثم يسأل تنفيذ المقارنة هل جزء المراكم أصغر من صفر، فيقرر أنه ليس كذلك، ويستنتج أنه لا حاجة لاقتراض. جزء واحد من النتيجة منحرف بمقدار واحد

مخطط التفاف الاقتراض في تخفيض Montgomery يقابل مقارنة الجزء الخاطئة بنشر الاقتراض الصحيح في حساب P-384 في HotPDF
إضافة الاقتراض إلى جزء كله واحدات تلتف إلى صفر، فلا يطبق الطرح في P-384 وP-521 بينما يخفي P-256 العيب

ينجو P-256 لأن أيا من أجزائه ليس كله واحدات، فلا تفيض الإضافة أبدا وتصادف الصيغة المعيبة أنها توافق الصحيحة. وذلك أسوأ نتيجة ممكنة لمجموعة اختبار: المنحنى الأكثر اختبارا يجتاز، والأقل اختبارا يفشل متقطعا حسب قيم المعاملات، ويظهر الإخفاق كنتيجة تحقق «توقيع غير صالح» على مستندات صحيحة تماما. حمل HotPDF تحصينا صريحا على P-384 لهذا السبب تحديدا، معيدا حالة غير متاحة بدل جواب خاطئ، حتى أثبت الحساب مقابل المتجهات المرجعية

كيف وُجد العيب فعلا

لم يوجد بقراءة الكود. التسلسل المثمر كان ميكانيكيا وهو قابل لإعادة الاستخدام. أولا استبعد الثوابت: أُعيد توليد كل جزء من p وR وR^2 بشكل مستقل وقورن جزءا بجزء، وهو ما يستبعد المصدر الأكثر شيوعا لعيوب المنحنيات. ثانيا عدّ الحساب لا الواجهة البرمجية: طبع إجراء تفريغ مؤقت القيم الوسطية لضرب Montgomery لكل من R^2 وx^3 وy^2 لنقطة معروفة، كي يمكن فحصها مقابل حقيقة محسوبة بشكل مستقل

أشارت تلك المقارنة مباشرة إلى الجاني. كانت سلسلة x صحيحة من طرف إلى طرف، بينما اختلف y^2 في جزء واحد بالضبط بمقدار واحد بالضبط. وفرق جزء واحد بمقدار واحد ليس عيب ضرب ولا عيب نشر حمل ولا عيب ثابت؛ إنه عيب سلسلة اقتراض، وسلسلة الاقتراض الوحيدة في الروتين هي الطرح الشرطي الأخير. كاد تفصيل واحد أن يخرج ذلك عن مساره: الثابت المرجعي المستخدم للتفريغ كُتب هو نفسه بترتيب بايتات خاطئ في المحاولة الأولى، ما أنتج عدم تطابق في قيمة y ووحي لفترة وجيزة بعيب ثان غير موجود. تحقق من ترتيب البايتات في حقيقتك المرجعية قبل أن تثق بها في اتهام كودك

مخطط سير لكيفية إيجاد عيب المنحنى في HotPDF بإعادة توليد الثوابت وتفريغ القيم الوسطية لـ Montgomery والمقارنة الفرقية بحقيقة المرآة
فرق جزء واحد بمقدار واحد بالضبط أشار مباشرة إلى سلسلة الاقتراض الوحيدة في الروتين، ومرجع معكوس البايتات كاد يضلل الصيد

الفخاخ المجاورة في الروتين نفسه

تعيش ثلاثة أنماط إخفاق أخرى في حدود أسطر قليلة من تلك المقارنة، وكلها الثلاثة كانت حية في مرحلة ما من التطوير

// 1. للمراكم جزء واحد فوق عرض القاسم. مقارنة الأجزاء L الدنيا فقط
//    تفوت الحالة التي يساوي فيها T تماما p زائد 2^(64*L)،
//    وهي تحدث لنصيب معتبر من المدخلات العشوائية لأن 2p
//    يتجاوز 2^256 لـ P-256 و2^384 لـ P-384
if (T[L] <> 0) or NotLessThanModulus(T, P, L) then
  SubtractModulus(T, P, L);

// 2. الطرح متعدد الأجزاء العام يحمل خطر الالتفاف نفسه: عندما
//    يكون Y[I] هو $FFFFFFFFFFFFFFFF يلتف Y[I] + Borrow إلى صفر ويجب
//    أن ينجو الاقتراض إلى الجزء التالي لا أن يصفَّر
Diff := X[I] - Y[I] - Borrow;
NextBorrow := Ord((X[I] < Y[I]) or ((X[I] = Y[I]) and (Borrow = 1)));

الثالث ليس كودا بل هو المصدر. كُتب العدد الأولي لـ P-521 في البداية بـ 130 رقما سداسيا عشريا بدل 131، ناقصا حرف F واحدا، ثم حسبت ثوابت Montgomery من ذلك العدد الأولي الخاطئ، فكانت الثوابت متسقة ذاتيا وخاطئة مجتمعة. معاملات المنحنى يجب أن تُشتق لا أن تُكتب: احسب R كـ (1 shl (64 * L)) mod p من العدد الأولي الذي تستخدمه فعلا، ثم تحقق متبادلا من R * R mod p مقابل القيمة التي يدعيها ثابت R^2 لديك. زوج ثوابت يتفقان مع بعضهما لا يثبت شيئا عن أي منهما

استراتيجية تحقق تتسع وراء منحنى واحد

التقنية التي جعلت X25519 وX448 قابلتين للمعالجة كانت كتابة تنفيذ مرآة بلغة تملك أعدادا صحيحة غير محدودة ثم نقل تدفق تحكم Pascal إليها سطرا بسطر. عندما تنتج المرآة الجواب الصحيح ولا ينتجه Pascal، يكون العيب زلة نقل، ويكشف التحقيق في القيمة الوسطية نفسها في التنفيذين موقعه في ثوان. وانتُقلت الأخطاء الثلاثة الكلاسيكية لسلم RFC 7748 جميعها بهذه الطريقة: تبديل بزمن ثابت أعاد سطره الثاني القيمة المتبادلة أصلا، وانعكاس نهائي أعاد z مرفوعا للأس سالب واحد بدل ضربه في X، وضرب بثابت صغير جمّع حواصل أنصاف الكلمات بـ or ثنائي وفقد الحمل

للمواد الاختبارية، خذ المتجهات كبايتات لا كنص. استخراج مفتاح خاص بنمط نصي هو الطريقة التي تُتهم بها معالجة صحيحة بخطأ انحراف بايت واحد يعيش كليا في خطوة الاستخراج. قص السداسي عشري من ترميز DER عند إزاحات معروفة وقارن مصفوفات البايتات

مع تصحيح سلسلة الاقتراض، تطابق المنحنيات الخمسة كلها المتجهات المرجعية المنشورة بايتا ببايت، ولم يعد HotPDF يحصن أيا منها. وإن كنت تدمج توقيعا معتمدا على الشهادات أو تشفير قائمة المستلمين، فالخلاصة العملية أن اختيار المنحنى صار قرار سياسة لا سؤال قدرة؛ وملفات التوقيع الشخصية ومزالق ترتيب البايتات في وجهة التوقيع مشمولة في جولة توقيع PAdES. وتفاصيل المكون ومصفوفة الخوارزميات المدعومة في صفحة منتج HotPDF Delphi PDF component