+++ title = "الأصدار الاول من بروتوكول OxideTalis" [extra] image = "/otmp_ar.png" lang = "ar-SA" dir = "rtl" add_toc = true +++ المؤلف: [عويتب](https://4rs.nl)\ التاريخ: 2024/6/1\ الاصدار: 1.0.0\ الحالة: مسودة ## نظرة عامة {#overview} بروتوكول OxideTalis هو بروتوكول تواصل بين طرفين بتشفير تام من طرف إلى طرف عبر مفتاح تشفير مشترك بينهم، يهدف البروتوكول إلى توفير سهولة التنقل من خادم إلى أخر بشكل إفتراضي وتوفير طريقة للتواصل بين الافراد في خوادم مختلفة بشكل مباشر بدون تواصل خادم المرسل وخادم المستقبل مع بعضهم البعض. ### الاهداف {#goals} - تواصل آمن بين طرفين مُشفر من ند إلى ند. - سهولة التنفيذ. - امكانية الإنتقال إلى خادم آخر. - امكانية التواصل مع اطراف خارج الخادم الخاص بالمرسل. - عدم الحاجة لتواصل المرسل مع الخادم الخاص به للتواصل مع اشخاص خارج الخادم. - عدم الحاجة ﻷسم مستخدم وكلمة مرور لتخويل المسخدم للمراسلة، والاكتفاء بالعنوان العام الخاص به. ### الاهداف الغير مرغوبة {#non-goals} - التواصل الجماعي. - المكالمات الصوتية أو الفيديو. ## العناوين العامة {#public-addresses} العنوان العام هو المفتاح العام الخاص بخوارزمية [Elliptic Curve Diffie-Hellman] مضغوط وهو يتكون من 33 بايت (264 بت) يتم ترميزه بترميز [base58] على سبيل المثال العنوان التالي `becZJsZZqGR7qBG8t1Pm4uy62jDTzJsabxnkARhr2syo`. يتم وضع العنوان العام في رأس (Header) الطلب (Request) بأسم `X-OTMP-PUBLIC` ويجب ان يكون نص [base58] صحيح مكون من 33 بايت (264 بت). ## أسم الخادم {#server-name} يكون أسم الخادم عنوان إلكتروني مثل `example.com` ولا يجب أن يكون الخادم نفسه، هو أسم فقط يشير إلى الخادم، على سبيل المثال، أسم الخادم `example.com` ولكن الخادم هو `otmp.example.com:443`، هكذا سوف يتم الإشارة لى مستخدمين هذا الخادم @becZJsZZqGR7qBG8t1Pm4uy62jDTzJsabxnkARhr2syo/example.com ويمكن إختصاره بالواجهات الرسومية بأخذ أول ثلاث أحرف و أخر ثلاث أحرف ووضع `..` بينهم، ليصبح بهذا الشكل @bec..syo/example.com. ### كيفية الإشارة {#referencing} يشير أسم الخادم إلى الخادم عبر المسار التالي /.well-known/oxidetalis/server سوف يتم إرسال طلب GET إلى هذا المسار و يجب أن يُرجع هذا المسار نص بتنسيق `application/json` يحتوي على المفتاح `otmp_server` ولذي يحتوي على مكان إستضافة الخادم والمنفذ الذي يستمع إليه، سوف يتم إرسال الطلب ببروتوكول https و يجب أن يدعم الخادم https و يجب ان تكون الشهادة موقعة من جهة موثوقة وليست موقعة ذاتياً[^1] ### مفتاح `otmp_server` محتوى هذا المفتاح يجب أن يكون نص، يتكون هذا النص من جزئين يفصل بينهم نقطتان رأسيتان، الجزء الأول هو مكان الإستضافة و الجزء الثاني هو المنفذ على سبيل المثال `"example.com:443"` و `"otmp.example.com:7294"` و `"93.184.215.14:7294"` و "[2606:2800:021f:cb07:6820:80da:af6b:8b2c]:7294". ### مثال
```json { "otmp_server": "otmp.example.com:443" } ```
> يجب على الخوادم عدم تخزين اسماء خوادم المرسلين، ويتم تحديده في الطلب المرسل من > قبلهم فقط، حيث أن المفتاح العام هو المعرف المشترك بين جميع الخوادم. ## مفتاح التشفير المشترك {#shared-encryption-key} يتم انشاء مفتاح التشفير المشترك عبر خوارزمية [Elliptic Curve Diffie-Hellman] secp256k1 حيث يقوم مرسل الرسالة بوضع العنوان العام الخاص بالمستقبِل لإنتاج المفتاح المشترك، بعد إنتاج المفتاح المشترك يتم ادخاله إلى دالة [HKDF] **بدون ملح** بخوارزمية [Sha256] وبعد ذلك يتم عمل له توسعة (expand) بدون معلومات (info) بطول 32 بايت (256 بت). ### التشفير {#encryption} سوف يتم استخدام [مفتاح التشفير المشترك] مفتاحاً للتشفير في خوارزمية [AES-256 CBC]، بعد تشفير الرسالة يتم وضع قيمة التهيئة (iv) في أخر الرسالة، ليكون اخر 16 بايت (128 بت) هي قيمة التهيئة (iv) التي سوف يستخدمها المستقبِل لفك تشفير الرسالة. مثال لمفتاح تشفير مشترك بترميز [base58] LKGKeuV3SRu1n3fez4SdboM3FT48vbBxHai9MbuWxb3 ## مفتاح الخادم العام {#server-public-key} مفتاح الخادم العام هو مثل العنواين العامة الخاصة بالمستخدمين، ولكنه خاص بالخادم، حيث ان الخادم سوف يقوم بأنشاء مفتاح مشترك بينه وبين مرسل الطلب (Request) ليتأكد من أن المرسل (صاحب العنوان العام) هو مالك هذا العنوان. يتم التأكد عبر مطابقة التوقيع الموجود في الطلب (Request). يتم جلب مفتاح الخادم العام من المسار /api/info سوف يتم إرسال طلب GET إلى هذا المسار و يجب أن يُرجع هذا المسار نص بتنسيق `application/json` يحتوي على المفتاح `public_key` ولذي قيمته نص المفتاح العام الخاص بالخادم بترميز [base58]، سوف يتم إرسال الطلب ببروتوكول https و يجب أن يدعم الخادم https و يجب ان تكون الشهادة موقعة من جهة موثوقة وليست موقعة ذاتياً[^1] > تم توضيح المفتاح العام هنا ([العناوين العامة](#public-addresses)) > حاول ان لا تقوم بتغيير المفتاح العام الخاص بالخادم بشكل مستمر، لآن العملاء سوف > يقومون بتخزينه بالعادة. ## توقيع الطلب {#request-signature} هو التوقيع الخاص بالطلب يتم وضعه في رأس الطلب (Header) بأسم `X-OTMP-SIGNATURE` او في بيانات ال [Websocket] في المفتاح `signature` بترميز [Hex] ويتم أستخدامه للتأكد من ان مرسل الطلب هو مالك المفتاح العام. ### إنشاء التوقيع {#create-signature} التوقيع يحتاج إلى ثلاث اشياء ليتم إنشائه - مفتاح التشفير المشترك. - جسم الطلب (body) أو بيانات الحدث (data) أو طريقة الطلب+المسار، مثال (GET/ws/chat) - ثواني الوقت الحالي للمنطقة الزمنية UTC+00:00 بتنسيق [Unix Time] (8 بايت أي 64 بت **big-endian**). - 16 بايت عشوائي (128 بت). يتم إدخال جسم الطلب (body) او بيانات الحدث في الـ[Websocket] إلى دالة [HMAC-SHA256] و إستخدام [مفتاح التشفير المشترك] مضافاً إليه الوقت الحالي (8 بايت) و الـ16 بايت العشوائي، أي المفتاح المستخدم في دالة [HMAC-SHA256] سوف يكون ``` مفتاح التشفير المشترك+الوقت الحالي+16 بايت عشوائي ``` بعد ذلك يتم أخذ نتيجة دالة [HMAC-SHA256] و إضافة الوقت المستخدم في الأعلى و الـ16 بايت المستخدمة في الأعلى و جميعهم بترميز [Hex]، مثال
``` bad035084e11bfd266c7b7dfa473d6603be551b3aa215f869776b75bf42ef31900000000665e1a696e6d776f65726e6664757265686a66 ```
بعد تحويله إلى بايتات سوف يكون المجموع 56 بايت، وسوف يكون التقسيم كالتالي - مخرج دالة [HMAC-SHA256]: من بايت 0 إلى بايت31. (التوقيع الذي سوف يتحقق منه الخادم) - الوقت: من بايت 32 إلى بايت 39. (الذي سوف يتم إضافته بعد [مفتاح التشفير المشترك]) - ال 16 بايت العشوائي: من بايت 40 إلى بايت 55. (سوف يتم إضافته بعد الوقت) سوف يتحقق الخادم من أن الوقت الذي في التوقيع لم يتجاوز الـ20 ثانية، وسوف يقوم الخادم بتخزين ال 16 بايت العشوائي في الكاش بمدة حياة 30 ثانية، ليتأكد الخادم من ان ال 16 بايت العشوائي لن يتم إستخدامهم في توقيع أخر، بالتالي ضمان عدم إرسال الطلب مرة أخرى من المهاجمين (ضمان أن التوقيع صالح لمرة واحدة فقط). ### شكل البيانات داخل إتصال الـWebsocket {#websocket-data} بعد الإتصال بـ[Websocket] مع الخادم، يكون تنسيق البيانات التي يتم تبادلها بين المرسل والخادم json ويجب عليها توفر المفاتيح التالية - `event`: إسم الحدث، على سبيل المثال إرسال رسالة او تحديث حالة الكتابة (التنسيق PascalCase). - `data`: البيانات الخاصة بالحدث. - `signature`: توقيع بيانات الحدث (data)، هذا التوقيع يكون بين المرسل وبين الخادم وليس المُستقبل. #### مثال لشكل البيانات في ال websocket {#websocket-data-example}
```json { "event": "EventName", "data": { "key": "value" }, "signature": "bad035084e11bfd266c7b7dfa473d6603be551b3aa215f869776b75bf42ef31900000000665e1a696e6d776f65726e6664757265686a66" } ```
> يمكن للخادم طلب أي شكل من البيانات، و يجب أن تكون المعلومات الحساسة مثل > الرسالة او الملف مُشفرة بين المُرسل و المُستقبل. ## طريقة التواصل {#communication} هنا سوف يتم توضيح طريقة التواصل بين طرفين في خادم واحد (تواصل داخلي)، وبين طرفين في خوادم مختلفة (تواصل خارجي) ### مفاهيم مهمة {#important-concepts} - التواصل الداخلي: هو تواصل طرفين في الخادم نفسه. - التواصل الخارجي: هو تواصل طرفين في خوادم مختلفة. - القائمة البيضاء: هي قائمة يمتلكها كل مستخدم في الخادم يوجد بها المستخدمين المسموح لهم بمراسلته. - القائمة السوداء: هي قائمة يمتلكها كل مستخدم في الخادم يوجد بها المستخدمين الغير مسموح لهم بإرسال طلب دردشة إليه. - قائمة الخادم السوداء: هي قائمة يقوم بوضعها مالك الخادم ليمنع خادمه من التواصل مع خوادم محددة او اشخاص محددين. - جدول الإتصالات الخارجية: هو جدول يتم حفظ به الرسائل الخارجية التي وصلت إلى المستخدم عندما لم يكن متصل بالخادم، ويتم مسحها بعد إرسالها له. - جدول طلبات الدردشة: هو جدول يتضمن طلبات الدردشة التي قاموا بإرسالها او إستقبالها افراد الخادم إلى/من افراد اخرين في نفس الخادم او في خوادم أخرى، ويتم مسح الطلب بعد وصول قبوله او رفضه. يتم الإستفادة من هذا الجدول لعدم إستقبال إشعارات قبول او رفض مزيفة. > سوف يتم استبدال العنوان العام بأسم **سارة** و **أحمد** لآن العناوين العامة > طويلة نسبياً ### التواصل الداخلي {#internal-communication} اولاً **يجب**[^2] عند فتحك لعميل التواصل أن تقوم بإنشاء إتصال [Websocket] بينك وبين الخادم الخاص بك، عبر هذا الإتصال سوف تستقبل الرسائل الجديدة من الخادم الخاص بك، وسوف تقوم بالتواصل من خلاله لإرسال الرسائل إلى افراد الخادم. لدينا الآن المرسلة **سارة** والمستقبِل **أحمد** و كلاهم في الخادم نفسه، سوف تقوم **سارة** بإرسال حدث [Websocket] تطلب من الخادم إرسال طلب دردشة إلى **أحمد** سوف يرد الخادم بأحد الأخطأ التالية، او لا يقوم بالرد إذا لم يكن هناك خطأ. #### إذا لم يكن هناك مستخدم بأسم **أحمد** في الخادم {#no-user} سوف يرجع الخادم خطأ ويخبر فيه **سارة** أنه ليس هناك مستخدم بهذا الأسم. #### إذا لم تكن **سارة** في قائمة **أحمد** البيضاء ولا السوداء {#not-in-white-or-black-list} سوف يقوم الخادم اولاً بإضافة **أحمد** إلى قائمة **سارة** البيضاء، وبعد ذلك إضافة الطلب في جدول طلبات دردشة **أحمد** **المُستقبلة** إذا كان غير متصل مع الخادم وسوف يضيفه إلى **المُرسلة** بالنسبة إلى **سارة**، لا يرجع الخادم أي خطأ في هذه الحالة. عندما يرد **أحمد** بالموافقة أو الرفض (عبر إتصال الـ[Websocket])، سوف يُعلم الخادم **سارة** بأن **أحمد** وافق أو رفض التواصل معها (عبر إتصال الـ[Websocket] أو إضافتها إلى جدول ليُعلمها عند تواصلها مع الخادم). إذا لم يوافق **أحمد** سوف يقوم الخادم بإضافة **سارة** إلى قائمة **أحمد** السوداء، و إذا وافق سوف يتم إضافتها إلى القائمة البيضاء. #### إذا كانت **سارة** في قائمة **أحمد** البيضاء {#in-white-list} سوف يرجع الخادم خطأ، يُعلم **سارة** أنها في قائمة **أحمد** البيضاء (يمكنها التواصل معه) #### إذا كانت **سارة** في قائمة **أحمد** السوداء {#in-black-list} سوف يرجع الخادم خطأ و يُعلم **سارة** انها في قائمة **أحمد** السوداء ولا يمكنه الدردشة معه. > يتم تخزين رسائل الطرفين مُشفرة في قاعدة البيانات الخاصة بالخادم ### التواصل الخارجي {#external-communication} لدينا الآن المرسلة **سارة** من `example1.com` والمستقبِل **أحمد** من `example2.com` سوف تقوم **سارة** بإرسال طلب Get إلى `example2.com` تطلب فيه الدردشة مع **أحمد**، **يجب** على **سارة** وضع الرأس `X-OTMP-SERVER` يحتوي على أسم الخادم الخاص بها، سوف يستخدم **أحمد** هذا الخادم لإرسال طلب القبول أو الرفض إليه إذا لم تكن **سارة** في قائمته السوداء ولا البيضاء، سوف يرد الخادم بأحد الردود التالية #### إذا لم يكن هناك مستخدم بأسم **أحمد** في الخادم {#no-user-external} سوف يرجع الخادم 404 و يُعلم **سارة** بأنه ليس لديه مستخدم بهذا الأسم. #### إذا لم تكن **سارة** في قائمة **أحمد** البيضاء ولا السوداء {#not-in-white-or-black-list-external} سوف يقوم خادم **أحمد** بإرسال طلب الدردشة إلى **أحمد** او يقوم بتخزين الطلب في جدول طلبات الدردشة **المٌستقبلة**، ويرد عليها بـ202، بعد ذلك تقوم **سارة** بطلب الخادم الخاص بها من إضافة **أحمد** إلى قائمتها البيضاء لتستقبل منه الرسائل مستقبلاً بدون حاجة **أحمد** إرسال طلب دردشة وإنتظار قبولها، سوف تقوم **سارة** ايضاً بطلب الخادم من إضافة **أحمد** إلى جدول طلبات الدردشة **المُرسلة**[^3] #### قبول أو رفض طلب الدردشة {#accept-or-reject-external} بعدما يستقبل **أحمد** طلب دردشة **سارة** و خادمها و عندما يريد قبول أو رفض الطلب سيقوم بالإرسال إلى النقطة /api/chat_response في خادم **سارة**، يجب على **أحمد** وضع عنوانه العام في الرأس `X-OTMP-PUBLIC` وتوقيع الطلب في `X-OTMP-SIGNATURE`، يجب أن يرسل طلب POST إلى النقطة مع جسم يوضح من مرسل الطلب (**سارة** في حالتنا) و إذا اراد قبوله أم لا. بعد ذلك إذا لم يكن لـ**سارة** إتصال [Websocket] سابق مع خادم **أحمد**، سوف تقوم بإرسال طلب دردشة ليتم ترقية الإتصال إلى [Websocket]، ونفس المسئلة مع **أحمد** إذا اراد التواصل مع **سارة** سوف يقوم بإرسال طلب دردشة ويتم ترقية الإتصال او إعلامه بوجود إتصال [Websocket] مفتوح. #### إذا كانت **سارة** في قائمة **أحمد** البيضاء {#in-white-list-external} سوف يقوم الخادم بترقية الإتصال إلى [Websocket] او إذا كانت **سارة** متصلة معه من قبل، سوف يقوم بإرجاع 400 ويخبر **سارة** بالتواصل معه عبر ال [Websocket]. #### إذا كانت **سارة** في قائمة **أحمد** السوداء او كانت هي او خادمها في قائمة الخادم السوداء {#in-black-list-external} سوف يرجع الخادم 403 مع توضيح السبب. #### أساسيات التواصل الخارجي {#external-communication-basics} - يجب على **سارة** فتح إتصال [Websocket] مع جميع الخوادم التي تريد التواصل مع افرادها. - لايتم تخزين الرسائل الخارجية التي يستقبلها الخادم بشكل دائم، يتم تخزينها فقط إذا لم يكن **أحمد** متصل بالخادم، ويتم مسحها بعد إرسالها إلى **أحمد**. - الرسائل والملفات تكون مشفرة بين **سارة** و **أحمد** وتكون موقعة للخادم المراد التواصل مع افراده. ## شكر و تقدير {#acknowledgment} شكراً للأشخاص التاليين على مراجعة و تحسين البروتوكول. - أمجد الشرفي <>: تحسين طريقة عمل التوقيع، و أقتراح الطريقة الحالية. {{ hr(data_content="وصلات") }} [^1]: لضمان عدم وجود شخص في المنتصف، يقوم بالتلاعب بالبيانات و الإطلاع عليها. [^2]: طالما انك عضو في الخادم، سوف يعتقد الخادم دائماً انك في إتصال [Websocket] معه، ولن يقوم بترقية أي إتصال إلى [Websocket] [^3]: يتم إضافة العنوان الخاص بـ**أحمد** في جدول طلبات الدردشة المُرسلة للتاكد من عدم إستقبال إشعارات قبول/رفض مزيفة هدفها الإزعاج. [Websocket]: https://en.wikipedia.org/wiki/WebSocket [HMAC-SHA256]: https://en.wikipedia.org/wiki/HMAC [مفتاح التشفير المشترك]: #shared-encryption-key [Hex]: https://en.wikipedia.org/wiki/Hexadecimal [Unix Time]: https://en.wikipedia.org/wiki/Unix_time [AES-256 CBC]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard [Sha256]: https://en.wikipedia.org/wiki/SHA-2 [HKDF]: https://en.wikipedia.org/wiki/HKDF [base58]: https://bitcoinwiki.org/wiki/base58 [Elliptic Curve Diffie-Hellman]: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman