تم إنشاء هذه الترجمة باستخدام التعلم الآلي وقد لا تكون دقيقة بنسبة 100%. عرض النسخة الإنجليزية

مواصفات LeaseSet المشفرة

إخفاء وتشفير وفك تشفير الـ leasesets المشفرة

نظرة عامة

تحدد هذه الوثيقة عملية التعمية والتشفير وفك التشفير لـ encrypted leasesets. لهيكل encrypted leaseset، انظر مواصفات الهياكل المشتركة . للخلفية حول encrypted leasesets، انظر الاقتراح 123 . للاستخدام في netDb، انظر وثائق netdb.

التعريفات

نُعرّف الدوال التالية المقابلة للوحدات البنائية التشفيرية المستخدمة لـ LS2 المشفر:

CSRNG(n) : مخرجات n-byte من مولد أرقام عشوائية آمن تشفيرياً.

بالإضافة إلى متطلب أن يكون CSRNG آمناً من الناحية التشفيرية (وبالتالي مناسباً لإنتاج مواد المفاتيح)، يجب أن يكون آمناً لاستخدام مخرجات من n-byte كمواد مفاتيح عندما تكون تسلسلات البايت التي تسبقها وتتبعها مباشرة مكشوفة على الشبكة (مثل في salt، أو حشو مشفر). التطبيقات التي تعتمد على مصدر قد لا يكون جديراً بالثقة يجب أن تقوم بتطبيق hash على أي مخرجات ستكون مكشوفة على الشبكة PRNG-REFS .

H(p, d) : دالة التشفير SHA-256 التي تأخذ سلسلة تخصيص p وبيانات d، وتنتج مخرجات بطول 32 بايت.

استخدم SHA-256 كما يلي:

H(p, d) := SHA-256(p || d)

STREAM : خوارزمية التشفير التدفقية ChaCha20 كما هو محدد في RFC-7539-S2.4 ، مع تعيين العداد الأولي على 1. S_KEY_LEN = 32 و S_IV_LEN = 12.

  • ENCRYPT(k, iv, plaintext) : يشفر النص الخام باستخدام مفتاح التشفير k، و nonce iv الذي يجب أن يكون فريداً لمفتاح k. يُرجع نصاً مشفراً بنفس حجم النص الخام. يجب أن يكون النص المشفر بأكمله غير قابل للتمييز عن العشوائي إذا كان المفتاح سرياً.

  • DECRYPT(k, iv, ciphertext) : يفك تشفير النص المشفر باستخدام مفتاح التشفير k، والقيمة العشوائية iv. يُرجع النص الواضح.

SIG : نظام التوقيع Red25519 (المطابق لـ SigType 11) مع إخفاء المفتاح. له الوظائف التالية:

  • DERIVE_PUBLIC(privkey) : يُرجع المفتاح العام المقابل للمفتاح الخاص المُعطى.

  • SIGN(privkey, m) : يُرجع توقيعاً بواسطة المفتاح الخاص privkey على الرسالة المعطاة m.

  • VERIFY(pubkey, m, sig) : يتحقق من التوقيع sig مقابل المفتاح العام pubkey والرسالة m. يُرجع true إذا كان التوقيع صالحاً، وfalse خلاف ذلك.

يجب أن يدعم أيضًا عمليات إخفاء المفاتيح التالية:

  • GENERATE_ALPHA(data, secret) : توليد alpha لأولئك الذين يعرفون البيانات وسر اختياري. يجب أن تكون النتيجة موزعة بشكل متطابق مع المفاتيح الخاصة.

  • BLIND_PRIVKEY(privkey, alpha) : يُخفي المفتاح الخاص، باستخدام قيمة سرية alpha.

  • BLIND_PUBKEY(pubkey, alpha) : يُعمِّي مفتاحاً عمومياً، باستخدام قيمة سرية alpha. لزوج مفاتيح معطى (privkey, pubkey) تنطبق العلاقة التالية:

BLIND_PUBKEY(pubkey, alpha) ==
DERIVE_PUBLIC(BLIND_PRIVKEY(privkey, alpha))

DH : نظام اتفاق المفتاح العام X25519. مفاتيح خاصة من 32 بايت، مفاتيح عامة من 32 بايت، ينتج مخرجات من 32 بايت. له الوظائف التالية:

  • GENERATE_PRIVATE() : ينشئ مفتاح خاص جديد.

  • DERIVE_PUBLIC(privkey) : يُرجع المفتاح العام المقابل للمفتاح الخاص المُعطى.

  • DH(privkey, pubkey) : ينتج سرًا مشتركًا من المفاتيح الخاصة والعامة المُعطاة.

HKDF(salt, ikm, info, n) : دالة اشتقاق مفاتيح تشفيرية تأخذ بعض المواد الأساسية للمفتاح ikm (والتي يجب أن تحتوي على إنتروبيا جيدة ولكن ليس مطلوباً أن تكون سلسلة عشوائية موحدة)، ومُلح بطول 32 بايت، وقيمة ‘info’ خاصة بالسياق، وتنتج مخرجاً بطول n بايت مناسب للاستخدام كمادة مفتاح.

استخدم HKDF كما هو محدد في RFC-5869 ، باستخدام دالة hash الـ HMAC SHA-256 كما هو محدد في RFC-2104 . هذا يعني أن SALT_LEN هو 32 بايت كحد أقصى.

التنسيق

يتكون تنسيق LS2 المشفر من ثلاث طبقات متداخلة:

  • طبقة خارجية تحتوي على معلومات النص الواضح اللازمة للتخزين والاسترجاع.
  • طبقة وسطى تتولى مصادقة العميل.
  • طبقة داخلية تحتوي على بيانات LS2 الفعلية.

الشكل العام يبدو كالتالي:

Layer 0 data + Enc(layer 1 data + Enc(layer 2 data)) + Signature

لاحظ أن LS2 المشفر مُعمى. الوجهة ليست موجودة في الرأس. موقع تخزين DHT هو SHA-256(نوع التوقيع || المفتاح العام المُعمى)، ويتم تدويره يومياً.

لا يستخدم رأس LS2 المعياري المحدد أعلاه.

الطبقة 0 (الخارجية)

النوع : 1 بايت

ليس في الرأس فعلياً، ولكن جزء من البيانات المغطاة بالتوقيع. يؤخذ من حقل في رسالة تخزين قاعدة البيانات.

نوع توقيع المفتاح العام المُقنع : 2 بايت، big endian

سيكون هذا دائماً من النوع 11، والذي يحدد مفتاح Red25519 مخفي.

المفتاح العام المُعمّى : الطول كما يُستدل عليه من نوع التوقيع

الطابع الزمني للنشر : 4 بايت، big endian

الثواني منذ العصر، تعود للصفر في عام 2106

انتهاء الصلاحية : 2 بايت، big endian

الإزاحة من الطابع الزمني المنشور بالثواني، 18.2 ساعة كحد أقصى

العلامات : 2 بايت

ترتيب البت: 15 14 … 3 2 1 0

  • البت 0: إذا كان 0، لا توجد مفاتيح غير متصلة؛ إذا كان 1، توجد مفاتيح غير متصلة
  • البتات الأخرى: تُضبط على 0 للتوافق مع الاستخدامات المستقبلية

بيانات المفتاح المؤقت : موجود إذا كان العلم يشير إلى مفاتيح غير متصلة

  • طابع زمني للانتهاء : 4 بايت، big endian. ثوانٍ منذ العصر، يعود للصفر في 2106
  • نوع التوقيع المؤقت : 2 بايت، big endian
  • المفتاح العام للتوقيع المؤقت : الطول كما هو مُضمّن بنوع التوقيع
  • التوقيع : الطول كما هو مُضمّن بنوع توقيع المفتاح العام المُعمّى. على الطابع الزمني للانتهاء، نوع التوقيع المؤقت، والمفتاح العام المؤقت. يتم التحقق منه باستخدام المفتاح العام المُعمّى.

lenOuterCiphertext : بايتان، big endian

outerCiphertext : lenOuterCiphertext بايت

بيانات الطبقة الأولى المشفرة. انظر أدناه لخوارزميات اشتقاق المفاتيح والتشفير.

التوقيع : الطول كما هو مُضمَّن في نوع التوقيع للمفتاح المُستخدم في التوقيع

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

الطبقة 1 (الوسطى)

الأعلام : 1 بايت

ترتيب البت: 76543210

  • البت 0: 0 للجميع، 1 لكل عميل، قسم المصادقة يتبع
  • البتات 3-1: مخطط المصادقة، فقط إذا تم تعيين البت 0 إلى 1 لكل عميل، وإلا 000
    • 000: مصادقة عميل DH (أو عدم وجود مصادقة لكل عميل)
    • 001: مصادقة عميل PSK
  • البتات 7-4: غير مستخدمة، تعيين إلى 0 للتوافق المستقبلي

بيانات مصادقة عميل DH : موجودة إذا تم تعيين بت العلامة 0 إلى 1 وتم تعيين بتات العلامة 3-1 إلى 000.

  • ephemeralPublicKey : 32 بايت
  • clients : 2 بايت، big endian. عدد إدخالات authClient التالية، 40 بايت لكل منها
  • authClient : بيانات التخويل لعميل واحد. انظر أدناه لخوارزمية التخويل لكل عميل.
    • clientID_i : 8 بايت
    • clientCookie_i : 32 بايت

بيانات مصادقة عميل PSK : موجودة إذا تم تعيين بت العلامة 0 إلى 1 وتم تعيين بتات العلامة 3-1 إلى 001.

  • authSalt : 32 بايت
  • clients : 2 بايت، big endian. عدد إدخالات authClient التي تتبع، 40 بايت لكل إدخال
  • authClient : بيانات التفويض لعميل واحد. انظر أدناه لخوارزمية التفويض لكل عميل.
    • clientID_i : 8 بايت
    • clientCookie_i : 32 بايت

innerCiphertext : الطول مستنتج من lenOuterCiphertext (أي بيانات متبقية)

بيانات الطبقة 2 المشفرة. انظر أدناه لخوارزميات اشتقاق المفاتيح والتشفير.

الطبقة 2 (الداخلية)

النوع : 1 بايت

إما 3 (LS2) أو 7 (Meta LS2)

البيانات : بيانات LeaseSet2 للنوع المحدد.

يتضمن الرأس والتوقيع.

اشتقاق مفتاح التعمية

نستخدم المخطط التالي لإخفاء المفاتيح، بناءً على Ed25519 و ZCash RedDSA ZCASH . توقيعات Red25519 تتم عبر منحنى Ed25519، باستخدام SHA-512 للتجميع.

نحن لا نستخدم الملحق A.2 من rend-spec-v3.txt الخاص بـ Tor TOR-REND-SPEC-V3 ، والذي له أهداف تصميم مشابهة، لأن المفاتيح العامة المُعماة (blinded public keys) الخاصة به قد تكون خارج المجموعة الفرعية ذات الرتبة الأولية، مما يحمل آثارًا أمنية غير معروفة.

الأهداف

  • يجب أن يكون مفتاح التوقيع العام في الوجهة غير المعماة Ed25519 (نوع التوقيع 7) أو Red25519 (نوع التوقيع 11)؛ لا يتم دعم أنواع توقيع أخرى
  • إذا كان مفتاح التوقيع العام غير متصل، فيجب أن يكون مفتاح التوقيع العام المؤقت أيضًا Ed25519
  • التعمية بسيطة حاسوبيًا
  • استخدام العمليات التشفيرية الموجودة
  • المفاتيح العامة المعماة لا يمكن إلغاء تعميتها
  • يجب أن تكون المفاتيح العامة المعماة على منحنى Ed25519 والمجموعة الفرعية ذات الترتيب الأولي
  • يجب معرفة مفتاح التوقيع العام للوجهة (الوجهة الكاملة غير مطلوبة) لاشتقاق المفتاح العام المعمى
  • توفير اختياري لسر إضافي مطلوب لاشتقاق المفتاح العام المعمى

الأمان

أمان مخطط الإخفاء (blinding scheme) يتطلب أن يكون توزيع alpha هو نفسه للمفاتيح الخاصة غير المخفية. ومع ذلك، عندما نخفي مفتاح Ed25519 خاص (sig type 7) إلى مفتاح Red25519 خاص (sig type 11)، يكون التوزيع مختلفًا. لتلبية متطلبات zcash القسم 4.1.6.1 ZCASH ، يجب استخدام Red25519 (sig type 11) للمفاتيح غير المخفية أيضًا، بحيث “لا يكشف الجمع بين مفتاح عام معاد التوزيع العشوائي والتوقيع (التوقيعات) تحت ذلك المفتاح عن المفتاح الذي أُعيد توزيعه عشوائيًا منه.” نحن نسمح بالنوع 7 للوجهات الموجودة، لكننا نوصي بالنوع 11 للوجهات الجديدة التي ستكون مشفرة.

التعريفات

B : النقطة الأساسية Ed25519 (المولد) 2^255 - 19 كما في ED25519-REFS

L : ترتيب Ed25519 هو 2^252 + 27742317777372353535851937790883648493 كما هو موضح في ED25519-REFS

DERIVE_PUBLIC(a) : تحويل مفتاح خاص إلى عام، كما في Ed25519 (الضرب في G)

alpha : رقم عشوائي مكون من 32 بايت معروف لأولئك الذين يعرفون الوجهة.

GENERATE_ALPHA(destination, date, secret) : توليد alpha للتاريخ الحالي، لأولئك الذين يعرفون الوجهة والسر. يجب أن تكون النتيجة موزعة بشكل متطابق مع مفاتيح Ed25519 الخاصة.

a : مفتاح التوقيع الخاص EdDSA أو RedDSA غير المُعمى بطول 32 بايت المستخدم لتوقيع الوجهة

A : مفتاح التوقيع العام غير المُقنع بحجم 32 بايت من نوع EdDSA أو RedDSA في الوجهة، = DERIVE_PUBLIC(a)، كما في Ed25519

a’ : المفتاح الخاص لتوقيع EdDSA المُعمى بحجم 32 بايت والمُستخدم لتوقيع leaseset المُشفر. هذا مفتاح خاص EdDSA صالح.

A’ : المفتاح العام للتوقيع EdDSA المخفي بطول 32 بايت في الوجهة، قد يتم إنشاؤه باستخدام DERIVE_PUBLIC(a’)، أو من A و alpha. هذا مفتاح عام صالح لـ EdDSA، على المنحنى وعلى المجموعة الفرعية ذات الترتيب الأولي.

LEOS2IP(x) : اقلب ترتيب البايتات المدخلة إلى little-endian

H*(x) : 32 بايت = (LEOS2IP(SHA512(x))) mod B، نفس الطريقة المستخدمة في Ed25519 hash-and-reduce

حسابات الإخفاء

يجب إنشاء مفاتيح alpha سرية جديدة ومفاتيح مُعماة (blinded) كل يوم (بتوقيت UTC).

يتم حساب alpha السري والمفاتيح المعماة كما يلي:

GENERATE_ALPHA(destination, date, secret)، لجميع الأطراف:

// secret is optional, else zero-length
A = destination's signing public key
stA = signature type of A, 2 bytes big endian (0x0007 or 0x000b)
stA' = signature type of blinded public key A', 2 bytes big endian (0x000b)
keydata = A || stA || stA'
datestring = 8 bytes ASCII YYYYMMDD from the current date UTC
secret = UTF-8 encoded string
seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64)
// treat seed as a 64 byte little-endian value
alpha = seed mod L

BLIND_PRIVKEY()، لمالك النشر الذي ينشر الـ leaseset:

alpha = GENERATE_ALPHA(destination, date, secret)
// If for a Ed25519 private key (type 7)
seed = destination's signing private key
a = left half of SHA512(seed) and clamped as usual for Ed25519
// else for a Red25519 private key (type 11)
a = destination's signing private key
// Addition using scalar arithmetic
blinded signing private key = a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L
blinded signing public key = A' = DERIVE_PUBLIC(a')

BLIND_PUBKEY()، للعملاء الذين يسترجعون الـ leaseset:

alpha = GENERATE_ALPHA(destination, date, secret)
A = destination's signing public key
// Addition using group elements (points on the curve)
blinded public key = A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)

كلتا طريقتي حساب A’ تعطيان نفس النتيجة، كما هو مطلوب.

التوقيع

يتم توقيع الـ leaseset غير المُعمّى بواسطة مفتاح التوقيع الخاص Ed25519 أو Red25519 غير المُعمّى ويتم التحقق منه باستخدام مفتاح التوقيع العام Ed25519 أو Red25519 غير المُعمّى (أنواع التوقيع 7 أو 11) كالمعتاد.

إذا كان مفتاح التوقيع العام غير متصل، يتم توقيع الـ leaseset غير المحجوب بواسطة مفتاح التوقيع الخاص المؤقت غير المحجوب Ed25519 أو Red25519 والتحقق منه باستخدام مفتاح التوقيع العام المؤقت غير المحجوب Ed25519 أو Red25519 (أنواع التوقيع 7 أو 11) كالمعتاد. راجع الملاحظات الإضافية أدناه حول المفاتيح غير المتصلة للـ leasesets المشفرة.

لتوقيع الـ leaseset المشفر، نستخدم Red25519 المبني على RedDSA ZCASH للتوقيع والتحقق باستخدام المفاتيح المعماة. توقيعات Red25519 تتم عبر منحنى Ed25519، باستخدام SHA-512 للتجميع.

Red25519 يشبه معيار Ed25519 باستثناء ما هو محدد أدناه.

حسابات التوقيع/التحقق

الجزء الخارجي من leaseset المشفر يستخدم مفاتيح وتوقيعات Red25519.

Red25519 مشابه لـ Ed25519. هناك اختلافان:

يتم توليد المفاتيح الخاصة Red25519 من أرقام عشوائية ثم يجب تقليلها باستخدام mod L، حيث L معرفة أعلاه. يتم توليد مفاتيح Ed25519 الخاصة من أرقام عشوائية ثم “تثبيتها” باستخدام القناع البتي للبايتات 0 و 31. هذا لا يتم فعله لـ Red25519. الدالتان GENERATE_ALPHA() و BLIND_PRIVKEY() المعرفتان أعلاه تولدان مفاتيح Red25519 خاصة صحيحة باستخدام mod L.

في Red25519، حساب r للتوقيع يستخدم بيانات عشوائية إضافية، ويستخدم قيمة المفتاح العام بدلاً من hash المفتاح الخاص. بسبب البيانات العشوائية، كل توقيع Red25519 مختلف، حتى عند توقيع نفس البيانات بنفس المفتاح.

Signing:
  T = 80 random bytes
  r = H*(T || publickey || message)
  (rest is the same as in Ed25519)

Verification:
  Same as for Ed25519

التشفير والمعالجة

اشتقاق الاعتمادات الفرعية

كجزء من عملية الإخفاء، نحتاج إلى التأكد من أن LS2 المشفر يمكن فقط فك تشفيره من قبل شخص يعرف مفتاح التوقيع العام المقابل للـ Destination. لا نحتاج إلى الـ Destination الكامل. لتحقيق ذلك، نستخرج بيانات اعتماد من مفتاح التوقيع العام:

A = destination's signing public key
stA = signature type of A, 2 bytes big endian (0x0007 or 0x000b)
stA' = signature type of A', 2 bytes big endian (0x000b)
keydata = A || stA || stA'
credential = H("credential", keydata)

سلسلة التخصيص تضمن أن بيانات الاعتماد لا تتعارض مع أي hash مستخدم كمفتاح بحث DHT، مثل hash الوجهة العادي.

بالنسبة لمفتاح مخفي معين، يمكننا بعد ذلك اشتقاق بيانات اعتماد فرعية:

subcredential = H("subcredential", credential || blindedPublicKey)

يتم تضمين الاعتماد الفرعي في عمليات اشتقاق المفاتيح أدناه، مما يربط تلك المفاتيح بمعرفة المفتاح العام للتوقيع الخاص بـ Destination.

تشفير الطبقة الأولى

أولاً، يتم إعداد المدخل لعملية اشتقاق المفتاح:

outerInput = subcredential || publishedTimestamp

بعد ذلك، يتم إنتاج salt عشوائي:

outerSalt = CSRNG(32)

ثم يتم اشتقاق المفتاح المستخدم لتشفير الطبقة 1:

keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
outerKey = keys[0:31]
outerIV = keys[32:43]

أخيراً، يتم تشفير وتسلسل النص الخام للطبقة 1:

outerCiphertext = outerSalt || ENCRYPT(outerKey, outerIV, outerPlaintext)

فك تشفير الطبقة الأولى

يتم تحليل الملح من النص المشفر للطبقة الأولى:

outerSalt = outerCiphertext[0:31]

ثم يتم اشتقاق المفتاح المستخدم لتشفير الطبقة 1:

outerInput = subcredential || publishedTimestamp
keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
outerKey = keys[0:31]
outerIV = keys[32:43]

وأخيراً، يتم فك تشفير النص المشفر للطبقة الأولى:

outerPlaintext = DECRYPT(outerKey, outerIV, outerCiphertext[32:end])

تشفير الطبقة الثانية

عندما يتم تمكين تفويض العميل، يتم حساب authCookie كما هو موصوف أدناه. عندما يتم تعطيل تفويض العميل، فإن authCookie هو مصفوفة بايت بطول صفر.

يتم التشفير بطريقة مشابهة للطبقة 1:

innerInput = authCookie || subcredential || publishedTimestamp
innerSalt = CSRNG(32)
keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
innerKey = keys[0:31]
innerIV = keys[32:43]
innerCiphertext = innerSalt || ENCRYPT(innerKey, innerIV, innerPlaintext)

فك تشفير الطبقة الثانية

عندما يكون تفويض العميل مُفعّلاً، يتم حساب authCookie كما هو موضح أدناه. وعندما يكون تفويض العميل مُعطّلاً، فإن authCookie هو مصفوفة بايتات بطول صفر.

يتم فك التشفير بطريقة مشابهة للطبقة 1:

innerInput = authCookie || subcredential || publishedTimestamp
innerSalt = innerCiphertext[0:31]
keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
innerKey = keys[0:31]
innerIV = keys[32:43]
innerPlaintext = DECRYPT(innerKey, innerIV, innerCiphertext[32:end])

التفويض لكل عميل

عندما يتم تمكين تخويل العميل للـ Destination، يحتفظ الخادم بقائمة من العملاء الذين يخولهم لفك تشفير بيانات LS2 المشفرة. تعتمد البيانات المخزنة لكل عميل على آلية التخويل، وتتضمن شكلاً من أشكال المواد الأساسية للمفاتيح التي ينشؤها كل عميل ويرسلها إلى الخادم عبر آلية آمنة خارج النطاق.

هناك بديلان لتطبيق التفويض لكل عميل:

تفويض العميل DH

يقوم كل عميل بتوليد زوج مفاتيح DH [csk_i, cpk_i]، ويرسل المفتاح العام cpk_i إلى الخادم.

معالجة الخادم

يقوم الخادم بإنتاج authCookie جديد وزوج مفاتيح DH مؤقت:

authCookie = CSRNG(32)
esk = GENERATE_PRIVATE()
epk = DERIVE_PUBLIC(esk)

ثم لكل عميل مخول، يقوم الخادم بتشفير authCookie إلى مفتاحه العام:

sharedSecret = DH(esk, cpk_i)
authInput = sharedSecret || cpk_i || subcredential || publishedTimestamp
okm = HKDF(epk, authInput, "ELS2_XCA", 52)
clientKey_i = okm[0:31]
clientIV_i = okm[32:43]
clientID_i = okm[44:51]
clientCookie_i = ENCRYPT(clientKey_i, clientIV_i, authCookie)

يضع الخادم كل مجموعة [clientID_i, clientCookie_i] في الطبقة 1 من LS2 المشفر، إلى جانب epk.

معالجة العميل

يستخدم العميل مفتاحه الخاص لاشتقاق معرف العميل المتوقع clientID_i ومفتاح التشفير clientKey_i ومتجه التهيئة للتشفير clientIV_i:

sharedSecret = DH(csk_i, epk)
authInput = sharedSecret || cpk_i || subcredential || publishedTimestamp
okm = HKDF(epk, authInput, "ELS2_XCA", 52)
clientKey_i = okm[0:31]
clientIV_i = okm[32:43]
clientID_i = okm[44:51]

ثم يبحث العميل في بيانات التفويض للطبقة الأولى عن إدخال يحتوي على clientID_i. إذا وُجد إدخال مطابق، يقوم العميل بفك تشفيره للحصول على authCookie:

authCookie = DECRYPT(clientKey_i, clientIV_i, clientCookie_i)

تفويض العميل بالمفتاح المشترك مسبقاً

كل عميل ينشئ مفتاحًا سريًا من 32 بايت psk_i، ويرسله إلى الخادم. بدلاً من ذلك، يمكن للخادم إنشاء المفتاح السري، وإرساله إلى عميل واحد أو أكثر.

معالجة الخادم

يقوم الخادم بإنشاء authCookie وملح جديدين:

authCookie = CSRNG(32)
authSalt = CSRNG(32)

ثم لكل عميل مُصرح له، يقوم الخادم بتشفير authCookie إلى مفتاحه المُشارك مسبقاً:

authInput = psk_i || subcredential || publishedTimestamp
okm = HKDF(authSalt, authInput, "ELS2PSKA", 52)
clientKey_i = okm[0:31]
clientIV_i = okm[32:43]
clientID_i = okm[44:51]
clientCookie_i = ENCRYPT(clientKey_i, clientIV_i, authCookie)

يضع الخادم كل مجموعة [clientID_i, clientCookie_i] في الطبقة 1 من LS2 المشفر، بالإضافة إلى authSalt.

معالجة العميل

يستخدم العميل مفتاحه المشترك مسبقاً لاشتقاق معرف العميل المتوقع clientID_i ومفتاح التشفير clientKey_i ومتجه التهيئة للتشفير clientIV_i:

authInput = psk_i || subcredential || publishedTimestamp
okm = HKDF(authSalt, authInput, "ELS2PSKA", 52)
clientKey_i = okm[0:31]
clientIV_i = okm[32:43]
clientID_i = okm[44:51]

ثم يبحث العميل في بيانات التخويل للطبقة الأولى عن إدخال يحتوي على clientID_i. إذا وُجد إدخال مطابق، يقوم العميل بفك تشفيره للحصول على authCookie:

authCookie = DECRYPT(clientKey_i, clientIV_i, clientCookie_i)

اعتبارات الأمان

كلا آليتي تفويض العميل المذكورتين أعلاه توفران الخصوصية لعضوية العميل. الكيان الذي يعرف فقط الوجهة يمكنه رؤية عدد العملاء المشتركين في أي وقت، لكن لا يمكنه تتبع العملاء الذين يتم إضافتهم أو إلغاؤهم.

يجب على الخوادم أن تعشوئ ترتيب العملاء في كل مرة تُنشئ فيها leaseSet مشفر من النوع الثاني، لمنع العملاء من معرفة موضعهم في القائمة واستنتاج متى تم إضافة عملاء آخرين أو إلغاؤهم.

قد يختار الخادم إخفاء عدد العملاء المشتركين عبر إدراج إدخالات عشوائية في قائمة بيانات التفويض.

مزايا تخويل العميل DH
  • أمان المخطط لا يعتمد فقط على التبادل خارج النطاق لمواد مفاتيح العميل. المفتاح الخاص للعميل لا يحتاج أبداً لمغادرة جهازه، وبالتالي فإن الخصم القادر على اعتراض التبادل خارج النطاق، ولكن لا يستطيع كسر خوارزمية DH، لا يمكنه فك تشفير LS2 المشفر، أو تحديد المدة التي يُمنح فيها العميل الوصول.
عيوب تفويض عميل DH
  • يتطلب N + 1 عمليات DH على جانب الخادم لـ N عميل.
  • يتطلب عملية DH واحدة على جانب العميل.
  • يتطلب من العميل توليد المفتاح السري.
مزايا تفويض العميل PSK
  • لا يتطلب عمليات DH.
  • يسمح للخادم بتوليد المفتاح السري.
  • يسمح للخادم بمشاركة نفس المفتاح مع عدة عملاء، إذا رغب في ذلك.
عيوب تخويل العميل بـ PSK
  • أمان المخطط يعتمد بشكل حاسم على التبادل خارج النطاق لمواد مفتاح العميل. يمكن للخصم الذي يعترض التبادل لعميل معين فك تشفير أي LS2 مشفر لاحق يكون هذا العميل مخولاً له، بالإضافة إلى تحديد متى يتم إلغاء وصول العميل.

leaseSet مشفر مع عناوين Base 32

لا يمكنك استخدام عنوان base 32 تقليدي لـ LS2 مشفر، حيث يحتوي فقط على hash الوجهة. لا يوفر المفتاح العام غير المحجوب. لذلك، عنوان base 32 وحده غير كافٍ. يحتاج العميل إما إلى الوجهة الكاملة (التي تحتوي على المفتاح العام)، أو المفتاح العام بحد ذاته. إذا كان لدى العميل الوجهة الكاملة في دفتر العناوين، ودفتر العناوين يدعم البحث العكسي بواسطة hash، فيمكن استرجاع المفتاح العام.

لذا نحتاج إلى تنسيق جديد يضع المفتاح العام بدلاً من الـ hash في عنوان base32. يجب أن يحتوي هذا التنسيق أيضاً على نوع التوقيع للمفتاح العام، ونوع التوقيع لمخطط الـ blinding. إجمالي المتطلبات هو 32 + 3 = 35 بايت، مما يتطلب 56 حرفاً في base 32، أو أكثر لأنواع المفاتيح العامة الأطول.

data = ((1 byte flags || 1 byte unblinded sigtype || 1 byte blinded sigtype) XOR checksum) || 32 byte pubkey
address = Base32Encode(data) || ".b32.i2p"

نستخدم نفس اللاحقة “.b32.i2p” كما هو الحال مع عناوين base 32 التقليدية. يتم تحديد عناوين encrypted leasesets بواسطة 56 حرفاً مُرمزاً (35 بايت مفكوكاً)، مقارنة بـ 52 حرفاً (32 بايت) للعناوين التقليدية base 32. يجب أن تكون البتات الخمس غير المستخدمة في نهاية b32 تساوي 0.

لا يمكنك استخدام leaseSet مشفر من النوع LS2 لـ bittorrent، بسبب ردود الإعلان المضغوطة التي تبلغ 32 بايت. الـ 32 بايت تحتوي على الـ hash فقط. لا يوجد مساحة للإشارة إلى أن الـ leaseset مشفر، أو أنواع التوقيع.

راجع مواصفات التسمية أو الاقتراح 149 للحصول على مزيد من المعلومات حول التنسيق الجديد.

leaseSet مشفر مع مفاتيح غير متصلة

بالنسبة لـ leasesets المشفرة مع المفاتيح غير المتصلة، يجب أيضاً إنتاج المفاتيح الخاصة المعماة في وضع عدم الاتصال، مفتاح واحد لكل يوم.

نظراً لأن كتلة التوقيع الاختيارية غير المتصلة بالإنترنت موجودة في الجزء النصي الواضح من leaseset المشفر، يمكن لأي شخص يقوم بكشط floodfills استخدام هذا لتتبع leaseset (ولكن ليس فك تشفيره) على مدى عدة أيام. لمنع هذا، يجب على مالك المفاتيح إنشاء مفاتيح مؤقتة جديدة لكل يوم أيضاً. يمكن إنشاء كل من المفاتيح المؤقتة والمعماة مسبقاً، وتسليمها إلى router في دفعة واحدة.

لا يوجد تنسيق ملف محدد لتعبئة مفاتيح مؤقتة ومخفية متعددة وتوفيرها للعميل أو router. لا يوجد تحسين محدد لبروتوكول I2CP لدعم leaseSet مشفرة بمفاتيح غير متصلة.

ملاحظات

  • خدمة تستخدم leasesets مشفرة ستنشر النسخة المشفرة إلى floodfills. ومع ذلك، من أجل الكفاءة، ستقوم بإرسال leasesets غير مشفرة إلى العملاء في رسالة garlic المغلفة، بمجرد المصادقة (عبر القائمة البيضاء، على سبيل المثال).
  • قد تقيد Floodfills الحد الأقصى للحجم إلى قيمة معقولة لمنع إساءة الاستخدام.
  • بعد فك التشفير، يجب إجراء عدة فحوصات، بما في ذلك أن الطابع الزمني الداخلي وتاريخ انتهاء الصلاحية يطابقان تلك الموجودة في المستوى الأعلى.
  • تم اختيار ChaCha20 بدلاً من AES. بينما تكون السرعات متشابهة إذا كان دعم AES الأجهزة متوفراً، فإن ChaCha20 أسرع بـ 2.5-3 مرات عندما لا يكون دعم AES الأجهزة متاحاً، مثل على أجهزة ARM منخفضة الأداء.

المراجع

Was this page helpful?