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

Proposal 153
مفتوح
Author chisana
Created 2019-08-04
Last Updated 2019-08-05

نظرة عامة

يستند هذا الاقتراح ويتطلب التغييرات من الاقتراح 152: أنفاق ECIES.

فقط الأنفاق المبنية من خلال القفزات التي تدعم صيغة BuildRequestRecord لأنفاق ECIES-X25519 يمكنها تنفيذ هذه المواصفات.

تتطلب هذه المواصفات تنسيق خيارات بناء النفق للإشارة إلى نوع تشفير طبقة النفق ونقل مفاتيح طبقة AEAD.

الأهداف

الأهداف من هذا الاقتراح هي:

  • استبدال AES256/ECB+CBC بـChaCha20 لتشفير طبقة النفق المثبتة وIV
  • استخدام ChaCha20-Poly1305 لحماية AEAD بين القفزات
  • عدم الكشف عن تشفير طبقة النفق القائم للمشاركين غير المشتركين في النفق
  • عدم إجراء أي تغييرات على طول الرسائل العلوية للنفق

معالجة الرسائل المثبتة في النفق

هذا القسم يصف التغييرات على:

  • المعالجة المسبقة + التشفير لبوايات الخارجة والداخلة
  • التشفير + معالجة المشاركين
  • التشفير + معالجة النقاط النهائية الخارج والداخل

للحصول على نظرة عامة على معالجة رسائل النفق الحالية، راجع المواصفات في Tunnel Implementation.

فقط التغييرات للراوترات التي تدعم تشفير طبقة ChaCha20 تتم مناقشتها.

لا يعتبر أي تغييرات للأنفاق المختلطة بتشفير AES للطبقة، حتى يمكن تصميم بروتوكول آمن لتحويل IV بعرض 128-بت من AES إلى nonce بعرض 64-بت من ChaCha20. يضمن فلتر بلوم التفرد للـIV بالكامل، ولكن يمكن أن يكون النصف الأول من IVs الفردية متطابقًا.

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

جميع البوابات والمشاركين في النفق سيحتاجون للحفاظ على فلتر بلوم للتحقق من صحة النونسيات المستقلة الاثنين.

nonceKey المذكور في جميع أنحاء هذا الاقتراح يحل محل IVKey المستخدم في تشفير الطبقة AES. يتم توليده باستخدام نفس KDF من الاقتراح 152.

تشفير AEAD للرسائل من قفزة إلى قفزة

سيتعين توليد مفتاح AEADKey فريد إضافي لكل زوج من القفزات المتتالية. سيتم استخدام هذا المفتاح من قبل القفزات المتتالية لتشفير وتفك تشفير الرسالة النفقية المشفرة الداخليًا في ChaCha20.

ستحتاج رسائل النفق إلى تقليل طول الإطار المشفر الداخلي بمقدار 16 بايت لإفساح المجال لـPoly1305 MAC.

لا يمكن استخدام AEAD على الرسائل مباشرة، حيث يلزم فك التشفير المتكرر بواسطة الأنفاق الخارجة. يمكن تحقيق فك التشفير المتكرر، بالطريقة التي يستخدم بها الآن، باستخدام ChaCha20 بدون AEAD.

+----+----+----+----+----+----+----+----+
  |    Tunnel ID      |   tunnelNonce     |
  +----+----+----+----+----+----+----+----+
  | tunnelNonce cont. |    obfsNonce      |
  +----+----+----+----+----+----+----+----+
  |  obfsNonce cont.  |                   |
  +----+----+----+----+                   +
  |                                       |
  +           Encrypted Data              +
  ~                                       ~
  |                                       |
  +                   +----+----+----+----+
  |                   |    Poly1305 MAC   |
  +----+----+----+----+                   +
  |                                       |
  +                   +----+----+----+----+
  |                   |
  +----+----+----+----+

  Tunnel ID :: `TunnelId`
         4 bytes
         the ID of the next hop

  tunnelNonce ::
         8 bytes
         the tunnel layer nonce

  obfsNonce ::
         8 bytes
         the tunnel layer nonce encryption nonce

  Encrypted Data ::
         992 bytes
         the encrypted tunnel message

  Poly1305 MAC ::
         16 bytes

  total size: 1028 Bytes

ستحصل القفزات الداخلية (بوجود قفزات تسبقها وتليها) على مفتاحي AEADKeys، أحدهما لفك تشفير طبقة AEAD للقفزة السابقة، والآخر لتشفير طبقة AEAD للقفزة التالية.

سيكون لدى جميع المشاركين الداخليين 64 بايت إضافي من مادة المفاتيح المدرجة في سجلات بناء طلباتهم.

ستحتاج الـGateway الخارجة والـ Endpoint الداخلي فقط إلى 32 بايت إضافي من بيانات المفتاح، لأنها لا تقوم بتشفير الرسائل عبر طبقة النفق بين بعضها البعض.

ينشئ الـGateway الخارجي مفتاح outAEAD الخاص به، ومن نفسه المفتاح inAEAD لأول قفزة خارجة.

ينشئ الـEndpoint الداخلي مفتاح inAEAD الخاص به، والذي يكون نفسه مثل المفتاح outAEAD للقفزة الأخيرة الداخلة.

القفزات الداخلية ستستلم مفتاح inAEADKey ومفتاح outAEADKey وسيستخدمان لفك AEAD الرسائل الواردة وتشفير الرسائل الصادرة على التوالي.

كمثال، في نفق به قفزات داخلية OBGW, A, B, OBEP:

  • مفتاح inAEADKey لـ A هو نفسه مثل مفتاح outAEADKey لـ OBGW
  • مفتاح inAEADKey لـ B هو نفسه مثل مفتاح outAEADKey لـ A
  • مفتاح outAEADKey لـ B هو نفسه مثل مفتاح inAEADKey لـ OBEP

المفاتيح فريدة لأزواج القفزات، لذلك مفتاح inAEADKey لـ OBEP سيكون مختلف عن مفتاح inAEADKey لـ A، ومفتاح outAEADKey لـ A مختلف عن مفتاح outAEADKey لـ B، وهكذا.

معالجة انتخابات الرسائل للبوابات وخالقي النفق

ستقوم البوابات بتجزئة وتجميع الرسائل بنفس الطريقة، مع تخصيص مساحة بعد إطار التعليمات-التجزئة للـPoly1305 MAC.

يمكن تقسيم رسائل I2NP الداخلية التي تحتوي على أطر AEAD (بما في ذلك MAC) عبر القطع، لكن أي قطع مفقودة ستؤدي إلى فشل فك تشفير AEAD (فشل التحقق من MAC) في النقطة النهاية.

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

عند دعم الأنفاق لتشفير طبقة ChaCha20، ستنشئ البوابات نونسيات 64-بت لكل مجموعة رسائل.

الأنفاق الداخلة:

  • تشفير الـIV ورسالة(رسائل) النفق باستخدام ChaCha20

  • استخدام نونسي tunnelNonce وobfsNonce بحجم 8-بايت نظرًا لعمر الأنفاق

  • استخدام نونسي obfsNonce لتشفير tunnelNonce

  • تدمير النفق قبل مجموعات رسائل تبلغ 2^(64 - 1) - 1: 2^63 - 1 = 9,223,372,036,854,775,807

    • الحد من استخدام النونسي موجود لمنع تصادم النونسيات 64-بت
    • من المستحيل تقريبًا الوصول إلى الحد العلوي من النونسيات، حيث يعادل هذا أكثر من ~15,372,286,728,091,294 رسائل/ثانية لأنفاق 10 دقائق
  • ضبط فلتر بلوم بناءً على عدد معقول من العناصر المتوقعة (128 رسالة/ثانية، 1024 رسالة/ثانية؟ سيتم تحديده لاحقًا)

تقوم بوابة النفق الداخلي (IBGW) بمعالجة الرسائل المستلمة من نقطة النهاية الخارجة لنفق آخر (OBEP).

في هذه المرحلة، تكون طبقة الرسالة الخارجية مشفرة باستخدام التشفير النقطة للنقطة للنقل. تكون رؤوس رسالة I2NP مرئية، في طبقة النفق، لـ OBEP و IBGW. الرسائل الداخلية لـ I2NP مغلفة في فصائل الثوم، ومشفرة باستخدام التشفير الطرف للطرف.

يقوم IBGW بمعالجة الرسائل مسبقًا في رسائل النفق المناسبة ويشفرة كما يلي:


// يولد IBGW نونسيات عشوائية، لضمان عدم الاصطدام في فلتر البلوم لنونسيه
  tunnelNonce = Random(len = 64-bits)
  obfsNonce = Random(len = 64-bits)
  // يشفر IBGW "بـChaCha20 كل من الرسائل المُعالجة مسبقًا بالنونسي الخاص به والمفتاح الخاص بطبقته
  encMsg = ChaCha20(msg = tunnel msg, nonce = tunnelNonce, key = layerKey)

  // تشفر الرسائل بالإطار المشفر باستخدام ChaCha20-Poly1305 باستخدام النونسي tunnelNonce ومفتاح outAEADKey
  (encMsg, MAC) = ChaCha20-Poly1305-Encrypt(msg = encMsg, nonce = tunnelNonce, key = outAEADKey)

سيتم تغيير صيغة رسالة النفق قليلًا، باستخدام نونسيتين بحجم 8 بايت بدلاً من IV بحجم 16 بايت. يتم إلحاق obfsNonce المستخدمة لتشفير النونسي مع tunnelNonce بحجم 8 بايت، وتشفيرها من قبل كل قفزة باستخدام tunnelNonce المشفر ومفتاح nonceKey الخاص بالقفزة.

بعد أن يتم فك تشفير الرسالة مسبقًا لكل قفزة، يقوم الـGateway الخارجي بتشفير ChaCha20-Poly1305 AEAD للمحتوى السري من كل رسالة نفق باستخدام tunnelNonce و مفتاح outAEADKey الخاص به.

الأنفاق الخارجة:

  • فك تشفير الرسائل بالنفق بشكل متكرر
  • تشفير ChaCha20-Poly1305 الرسالة التي تم فك تشفيرها مسبقًا المرتبطة بأطر الرسائل بدون مراجعه
  • استخدام نفس قواعد النونسي لطبقة الأنفاق كأنفاق داخلة
  • توليد نونسيات عشوائية لكل مجموعة من الرسائل المستخدمة في النفق


// للحصول على كل مجموعة من الرسائل، إنشاء نونسيات فريدة وعشوائية
  tunnelNonce = Random(len = 64-bits)
  obfsNonce = Random(len = 64-bits)

  // لكل قفزة، استخدم ChaCha20 على النونسي السابق الخاص بالنفق مع مفتاح IV الخاص بالقفزة الحالية
  tunnelNonce = ChaCha20(msg = prev. tunnelNonce, nonce = obfsNonce, key = hop's nonceKey)

  // لكل قفزة، فك تشفير ChaCha20 للرسالة الخاصة بالنفق باستخدام النونسي الخاص بالقفزة الحالي ومفتاح الطبقة
  decMsg = ChaCha20(msg = tunnel msg(s), nonce = tunnelNonce, key = hop's layerKey)

  // لكل قفزة، فك تشفير ChaCha20 للـobfsNonce باستخدام النونسي المشفر الخاص بالنفق الحالي والمفتاح nonceKey الخاص بالقفزة
  obfsNonce = ChaCha20(msg = obfsNonce, nonce = tunnelNonce, key = hop's nonceKey)

  // بعد معالجة القفزة، تشفير ChaCha20-Poly1305 لكل إطار بيانات مشفراً ``"مفكوك" `` مع النونسي الخاص بنفق القفزة الأول والمفتاح inAEADKey الخاص بالقفزة الأولى
  (encMsg, MAC) = ChaCha20-Poly1305-Encrypt(msg = decMsg, nonce = first hop's encrypted tunnelNonce, key = first hop's inAEADKey / GW outAEADKey)

معالجة المشاركين

سيتابع المشاركون الرسائل المرئية بنفس الطريقة، باستخدام فلاتر بلوم المتقادمة.

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

ستقوم القفزات بتشفير النونسي المستلم لمنع هجمات التأكيد بين القفزات السابقة والتالية، أي القفزات المتعاونة غير المتتابعة التي تمكن معرفة أنها تنتمي لنفس النفق.

للتحقق من صحة tunnelNonce وobfsNonce المستلمة، يقوم المشاركون بالتحقق من كل نونسي بشكل فردي ضد فلتر بلوم للتأكد من عدم التكرار.

بعد التحقق، يقوم المشارك:

  • يفك تشفير كل الرسائل الخاصة بالنفق باستخدام ChaCha20-Poly1305 لفك تشفير الإطار المحدث باستخدام النونسي المتلقى ومفتاح inAEADKey الخاص به
  • تشفير tunnelNonce باستخدام nonceKey الخاص به وobfsNonce المستلمة
  • تشفير كل إطارات البيانات المشفرة للرسائل الخاصة بالنفق باستخدام tunnelNonce المشفرة ومفتاح layerKey الخاص به
  • تشفير ChaCha20-Poly1305 لكل إطار بيانات مشفر بواسطة الرسالة الخاصة بالنفق باستخدام tunnelNonce المشفرة ومفتاح outAEADKey الخاص به
  • تشفير obfsNonce باستخدام nonceKey الخاص به وtunnelNonce المشفر
  • إرسال المجموعة {nextTunnelId، مشفرة (tunnelNonce || obfsNonce)، AEAD ciphertext || MAC} إلى القفزة التالية.

// للتحقق، ينبغي على قفزات النفق التحقق من فلتر بلوم لمدى تفرد كل نونسي مستلم
  // بعد التحقق، قُم بفك إطار AEAD عن طريق فك ChaCha20-Poly1305 لكل إطار مشفر للرسالة الخاصة بالنفق مع النونسي المستلم ومفتاح inAEADKey
  encTunMsg = ChaCha20-Poly1305-Decrypt(msg = received encMsg \|\| MAC, nonce = received tunnelNonce, key = inAEADKey)

  // تشفير ChaCha20 للنونسي الخاص بالنفق باستخدام النونسي و``nonceKey`` الخاص بالقفزة
  tunnelNonce = ChaCha20(msg = received tunnelNonce, nonce = received obfsNonce, key = nonceKey)

  // تشفير ChaCha20 لكل إطار بيانات مشفر للرسائل الخاصة بالنفق باستخدام النونسي المشفرة بالـ``layerKey`` الخاص بالقفزة
  encMsg = ChaCha20(msg = encTunMsg, nonce = tunnelNonce, key = layerKey)

  // لحماية AEAD، أيضًا نفذ فشي ChaCha20-Poly1305 لكل إطار رسائل خاص بالنفق باستخدام النونسي المشفرة ومفتاح outAEADKey الخاص بالقفزة
  (encMsg, MAC) = ChaCha20-Poly1305-Encrypt(msg = encMsg, nonce = tunnelNonce, key = outAEADKey)

  // تشفير ChaCha20 للـobfsNonce المستلمة باستخدام النونسي المشفر ومفتاح nonceKey الخاص بالقفزة
  obfsNonce = ChaCha20(msg = obfsNonce, nonce = tunnelNonce, key = nonceKey)

معالجة النقطة النهائية الداخلة

لأنفاق ChaCha20، سيتم استخدام المخطط التالي لفك تشفير كل رسالة خاصة بالنفق:

  • تحقق من صحة tunnelNonce وobfsNonce المستلمة بشكل مستقل ضد فلتر بلوم
  • فك تشفير باستخدام ChaCha20-Poly1305 للإطار المشفر باستخدام النونسي المستلم وinAEADKey
  • فك تشفير لإطار البيانات المشفرة باستخدام النونسي المستلم & مفتاح layerKey الخاص بالقفزة
  • فك تشفير obfsNonce باستخدام مفتاح nonceKey الخاص بالقفزة والنونسي المستلم للحصول على الـobfsNonce السابق
  • فك تشفير النونسي المستلم باستخدام مفتاح nonceKey الخاص بالقفزة وobfsNonce المفكّة للحصول على النونسي السابق
  • فك تشفير البيانات المشفرة باستخدام النونسي المفكّة & مفتاح الطبقة السابق
  • تكرار الخطوات لفك تشفير النونسي والطبقة لكل قفزة في النفق، حتى تصل إلى الـIBGW
  • لا تحتاج فك تشفير إطار AEAD إلا في الجولة الأولى

// للجولة الأولى، فك تشفير كل إطار بيانات مشفر + MAC باستخدام ChaCha20-Poly1305
  // باستخدام النونسي المستلم و``inAEADKey``
  msg = encTunMsg \|\| MAC
  tunnelNonce = received tunnelNonce
  encTunMsg = ChaCha20-Poly1305-Decrypt(msg, nonce = tunnelNonce, key = inAEADKey)

  // تكرار لكل قفزة في النفق حتى تصل إلى الـIBGW
  // لكل جولة، فك تشفير ChaCha20 لكل طبقة قفزة على كل إطار بيانات مشفر بالرسائل
  // استبدل النونسي المستلم بالنونسي المفك لكل جولة لكل قفزة
  decMsg = ChaCha20(msg = encTunMsg, nonce = tunnelNonce, key = layerKey)
  obfsNonce = ChaCha20(msg = obfsNonce, nonce = tunnelNonce, key = nonceKey)
  tunnelNonce = ChaCha20(msg = tunnelNonce, nonce = obfsNonce, key = nonceKey)

التحليل الأمني لتشفير طبقة النفق ChaCha20+ChaCha20-Poly1305

التحول من AES256/ECB+AES256/CBC إلى ChaCha20+ChaCha20-Poly1305 له عدد من المزايا واعتبارات أمنية جديدة.

أكبر الأمور الأمنية التي يجب مراعاتها هي أنه يجب أن تكون نونسيات ChaCha20 و ChaCha20-Poly1305 فريدة لكل رسالة، طوال عمر المفتاح المستخدم.

إذا فشلنا في استخدام نونسيت فريدة مع نفس المفتاح على رسائل مختلفة، فإن هذا سيفشل ChaCha20 و ChaCha20-Poly1305.

استخدام obfsNonce الملحق يسمح لـ IBEP بفك تشفير tunnelNonce لكل طبقة تشفير القفزة، واستعادة النونسي السابق.

الـobfsNonce بجانب tunnelNonce لا يكشف عن أي معلومات جديدة لقفزات النفق، حيث يتم تشفير obfsNonce باستخدام tunnelNonce المشفرة. وهذا يسمح أيضًا لـ IBEP باستعادة الـobfsNonce السابق بطريقة مشابهة لاستعادة tunnelNonce.

أكبر ميزة أمنية هي أنه لا توجد هجمات تأكيد أو هجمات قاعية ضد ChaCha20، واستخدام ChaCha20-Poly1305 بين القفزات يضيف حماية AEAD ضد التلاعب في النص المشفر من مهاجمين MITM الخارجيين.

توجد هجمات قاعية عملية ضد AES256/ECB + AES256/CBC، عند إعادة استخدام المفتاح (كما في تشفير طبقة النفق).

هجمات القاعية ضد AES256/ECB لن تعمل، بسبب استخدام التشفير المزدوج، ويتم التشفير على وحدة واحدة (IV النفق).

هجمات القاعية على AES256/CBC لن تعمل، لأنه لا يتم استخدام أي تعبئة. إذا تغير طول الرسالة الخاصة بالنفق يومًا إلى طول غير قابل للقسمة على 16، فلن يظل AES256/CBC عرضة للهجوم بسبب رفض IVs المكررة.

كلا الهجومين أيضًا يتم إيقافهما عن طريق حظر المكالمات المتعددة للقاعدة باستخدام نفس الـIV، حيث يتم رفض الـIVs المكررة.

المراجع