توضيح أنواع تشفير AES لماذا تتفوق GCM على CBC في معظم الحالات (وأحيانًا لا)

نُشرت في

الخوارزمية AES وحدها ليست خيارًا كاملًا. الوضع — CBC، CTR، GCM، ECB — يحدد كل شيء حول ما إذا كانت تشفيرك آمنًا حقًا. إليك التحليل العملي الذي يحتاجه المطورون.

توضيح أنواع تشفير AES: لماذا يتفوق GCM على CBC في معظم الحالات (وأحيانًا لا يتفوق) 1
إعلان · حذف؟

عندما تقول الوثائق "استخدم AES-256"، فإن هذا يُعد نصيحة غير مكتملة. إن AES هو خوارزمية تشفير مُقسّمة — تُشفّر مُقتطفًا بحجم 128 بت في كل مرة. فإن نوع التشغيل هو ما يحدد كيفية معالجة AES للبيانات الطويلة أكثر من 16 بيت، وكيف يحميك من الهجمات التي يمكن أن تراقب أو تُغيّر النص المُشفّر. إذا أخطأت في هذا الجانب، فإنك تنتهي ببيانات مُشفّرة تُكشف هيكل الملفات، أو أنظمة عرضها معرضة للهجمات التي تُغيّر بتقسيم الأرقام.

يبدو التصريح الكامل للخوارزمية على النحو التالي AES-256-GCM أو AES-128-CBC — حجم المفتاح متبوعًا بوضع التشغيل. يغطي هذا المقال ما يفعله كل وضع، ولماذا يُعد وضع GCM الافتراضي الصحيح، وما هي الحالات التي يمكن أن تُستخدم فيها بدائل أخرى.

أولًا، لماذا يُعتبر وضع ECB ميمًا وليس مجرد سخرية

ECB (الكود الكهربائي) هو الوضع البسيط. يتم تشفير كل مُقتطف بحجم 16 بيت من النص المُدخل بشكل مستقل باستخدام نفس المفتاح. وهذا يعني أن المُقتطفات المتماثلة تُنتج مُقتطفات متماثلة في النص المُشفّر.

العرض الكلاسيكي هو التصوير المُشفّر لبنتيكس (Tux) بالطريقة ECB. يتم تشفير الصورة بشكل مُقسّم، ولكن لأن معظم مناطق الصورة من ألوان متماثلة، فإن الصورة المُشفّرة تُظهر بوضوح شكل البنتيكس. التشفير منطقيًا صحيح — البيانات مُختلطة — ولكن النمط يُحتفظ به.

في الممارسة، هذا يهم في كل حالة توجد فيها تكرار في النص المُدخل: صفوف قاعدة البيانات ذات المقدمة المشتركة، عناوين الملفات، الحقول المُملوءة. يُكشف فيه الهيكل. لا توجد حالة مقبولة لاستخدام وضع ECB في الكود الجديد. إذا كنت تُحافظ على كود يستخدم وضع ECB: استبدل هذا الكود.

الوضع المهم الذي يجب معرفته

CBC — الوضع الذي يستخدمه معظم الكود القديم

يُستخدم وضع التسلسل التبادلي (Cipher Block Chaining) لإجراء تشفير كل مُقتطف من النص المُدخل مع مُقتطف التشفير السابق قبل التشفير. هذا يحل مشكلة نمط ECB — حيث أن المُقتطفات المتماثلة تُنتج مُقتطفات مختلفة لأن التسلسل يعتمد على ما سبق.

يتطلب CBC مُدخل تمهيد (IV) — قيمة عشوائية بحجم 16 بيت تُستخدم كمُدخل للسلسلة في المُقتطف الأول. لا يلزم أن تكون هذه القيمة سرية، ولكن يجب أن تكون عشوائية وتم إرسالها مع التشفير المُشفّر.

المشكلة مع CBC: توفّر السرية — Python الكاملية. يمكن للاختراق الذي يُغيّر النص المُشفّر أثناء النقل أن يُغيّر أرقام معينة في الناتج المُفكّك بطريقة متوقعة. وهذا هو الأساس للهجمات على التعبئة، والتي أُسهمت في تدمير أنظمة حقيقية (POODLE، BEAST، Lucky Thirteen). إذا استخدمت CBC دون مُدخل تحقق من الكمال (Message Authentication Code) لتأكيد الكمال، فإنك تكون معرضًا للخطر. يُعرف هذا النمط باسم "تشفير ثم تحقق من الكمال" — تشفير أولًا، ثم تحقق من الكمال باستخدام HMAC، ثم تحقق من الكمال قبل التفكك. خطأ في هذا الترتيب هو خطأ شائع.

CBC أيضًا متسلسل — لا يمكن توازي التشفير (لأن كل مُقتطف يعتمد على المُقتطف السابق)، وعمل التفكك فقط جزئيًا متوازي.

CTR — سلوك خوارزمية التدفق من خوارزمية تشفير مُقسّمة

يُحوّل وضع CTR AES إلى خوارزمية تدفق. بدلًا من تشفير النص المُدخل مباشرة، يتم تشفير قيم العد التدريجي وعمل عملية XOR مع النص المُدخل. هذا يعني أن وضع CTR لا يحتاج إلى تعبئة (يمكنه العمل على بيانات من أي طول)، ويمكنه التوازي الكامل في الاتجاهين، ويسمح بالوصول العشوائي إلى أي موقع في النص المُشفّر عند التفكك.

يستخدم CTR قيمة "مُستخدم مرة واحدة" (nonce) بدلًا من مدخل تمهيد كامل. يجب أن تكون القيمة المُستخدم مرة واحدة فريدة لكل رسالة باستخدام نفس المفتاح — إعادة استخدام القيمة المُستخدم مرة واحدة مع نفس المفتاح تُكشف عن XOR بين المُقتطفين، وهو أمر مهلك. بخلاف CBC، لا يحتوي CTR على حماية كمالية. نفس القصة: يجب أن تستخدم "تشفير ثم تحقق من الكمال" إذا كنت ترغب في مقاومة التلاعب.

يُعد CTR منطقيًا عندما تحتاج إلى خصائص خوارزمية التدفق — ملفات كبيرة، تفكك عشوائي، أو مواقف ذات تدفق عالٍ حيث يُهم التوازي — وعندما تُعالج الطبقات المُتحقق من الكمال بشكل منفصل.

GCM — تشفير مُتحقق من الكمال، خطوة واحدة

وضع Galois/Counter Mode هو وضع CTR مع مُدخل تحقق من الكمال (GHASH). تُحصل على سرية وكمالية في خطوة واحدة. يُسمح للمستقبل بتأكيد أن النص المُشفّر لم يُغيّر قبل التفكك. لا حاجة لخطوة HMAC منفصلة، ولا فرصة لخطأ في ترتيب "تشفير ثم تحقق من الكمال".

يُدعم GCM أيضًا البيانات المُتحقق من الكمال الإضافية (AAD) — البيانات التي تُتحقق من الكمال ولكن لا تُشفّر. هذا مفيد للعناوين، البيانات المُتخصصة، أو أي بيانات تحتاج إلى حماية من التلاعب ولكن لا تحتاج إلى سرية. يتم التحقق من AAD مع مُدخل التحقق من الكمال مع التشفير المُشفّر.

يُستخدم مُدخل التحقق من الكمال في GCM بحجم 96 بت (12 بيت) بشكل افتراضي. مثل CTR، فإن إعادة استخدام المُدخل المُستخدم مرة واحدة هو أمر مهلك — إعادة استخدام المُدخل مع نفس المفتاح في GCM تُكشف عن المُدخل المُشفّر والخيار المُستخدم للتحقق من الكمال (H)، مما يُهدد أمن النظام بالكامل. يجب دائمًا توليد المُدخلات باستخدام مُولد عشوائي مُعتمد على الأمان؛ لا تُستخرج من عدادات متسلسلة إلا إذا كان لديك نظام توزيع عالمي مُحكم.

GCM يمكن أن يكون متوازيًا ولا يحتاج إلى تعبئة. هو الاقتراح القياسي في TLS 1.3، وبروتوكول الإشارة، ومعظم المكتبات التشفيرية الحديثة. إذا كنت تكتب كودًا جديدًا، فإن GCM هو الافتراض.

مقارنة بين الوضع

الوضعمُعتمد على التحققمُتاح للتواسعيحتاج إلى تعبئةمخاطر إعادة استخدام المُدخل/المُدخل التمهيديإدانة
ECBلانعمنعمغير متوفر (لا يوجد مُدخل تمهيدي)لا تستخدمه أبدًا
CBCلا (أضف تحقق من الكمال)تشفير: لا / تفكك: نعمنعممعتدلمُستخدم فقط في الأنظمة القديمة
CTRلا (أضف تحقق من الكمال)نعملامهم — إعادة استخدامه يؤدي إلى تسريب المُدخلاتاستخدام محدود
GCMنعم (مدمج)نعملامهم — إعادة استخدامه يؤدي إلى تدمير كاملالاختيار الافتراضي

AES-256-GCM في Node.js

إليك تطبيق كامل للاستفادة من التشفير والفك التشفير باستخدام الوحدة المدمجة في Node crypto — لا يتطلب أي اعتمادات إضافية:

const crypto = require('crypto');

const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32; // 256 bits
const NONCE_LENGTH = 12; // 96 bits — GCM default
const TAG_LENGTH = 16; // 128-bit auth tag

function encrypt(plaintext, key) {
  const nonce = crypto.randomBytes(NONCE_LENGTH);
  const cipher = crypto.createCipheriv(ALGORITHM, key, nonce, {
    authTagLength: TAG_LENGTH,
  });

  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();

  // Prepend nonce + tag to ciphertext for storage/transmission
  return Buffer.concat([nonce, tag, encrypted]);
}

function decrypt(ciphertext, key) {
  const nonce = ciphertext.subarray(0, NONCE_LENGTH);
  const tag = ciphertext.subarray(NONCE_LENGTH, NONCE_LENGTH + TAG_LENGTH);
  const data = ciphertext.subarray(NONCE_LENGTH + TAG_LENGTH);

  const decipher = crypto.createDecipheriv(ALGORITHM, key, nonce, {
    authTagLength: TAG_LENGTH,
  });
  decipher.setAuthTag(tag);

  // Throws if auth tag doesn't match — do not catch this silently
  return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8');
}

// Generate a key (do this once; store it securely)
const key = crypto.randomBytes(KEY_LENGTH);

const message = 'Hello, authenticated encryption.';
const ciphertext = encrypt(message, key);
console.log('Encrypted:', ciphertext.toString('hex'));

const plaintext = decrypt(ciphertext, key);
console.log('Decrypted:', plaintext); // Hello, authenticated encryption.

أمور يجب ملاحظتها حول هذا الكود:

  • يُولّد المُدخل المُستخدم مرة واحدة لكل عملية تشفيرcrypto.randomBytes بشكل آمن. لا تُستبدل بعداد إلا إذا فهمت مشكلة التوازي الموزع.
  • يُخزن المُدخل والمُدخل التحقق من الكمال مع التشفير المُشفّر — يجب أن يُنقل مع البيانات المُشفّرة. المُدخل هو علني، والمُدخل التحقق من الكمال هو علني. فقط المفتاح هو السر.
  • decipher.final() يُنذر عند فشل التحقق من الكمال — هذا هو السلوك الصحيح. لا تُعالج هذه الحالة بشكل سري وتعيد النص المُفكّك جزئيًا. فشل التحقق من الكمال يعني أن البيانات تم تلاعبها أو أن المفتاح خاطئ.
  • إدارة المفتاح هي الجزء الصعبcrypto.randomBytes(32) يُعطيك مفتاح جيد، ولكن حيث تُخزن وتُعادل المفتاح يهم أكثر من اختيار الخوارزمية. استخدم مدير الأسرار، لا مفتاح مُكتوب بشكل مُباشر.

تريد اختبار أنواع التشفير تفاعليًا؟ أداة IO Tools’ للاستفادة من التشفير/الفك التشفير لـ AES تُسمح لك بتمثيل التشفير والفك التشفير باستخدام وضع CBC ووضع GCM في المتصفح — مفيد لتأكيد التوافق أو تدقيق تكامل. لاستنتاج مفتاح آمن بحجم 256 بت، استخدم مولد مفتاح AES.

مُدخلات الـ IV وNonce: القواعد التي تهم حقًا

استخدام خاطئ لـ Nonce/IV يسبب أكثر هجمات في الواقع من اختيار الخوارزمية. القواعد:

  • أعد توليد Nonce/IV باستخدام مولد عشوائي مُعتمد على الأمانcrypto.randomBytes() في Node، os.urandom() في بايثون، SecureRandom في Java. ليس Math.random(). ليس وقتًا مُحددًا. ليس عدادًا متسلسلًا إلا إذا كان عدادًا عالميًا مُدارة بعناية مع ضمانات للتوافق.
  • إعادة استخدام Nonce في GCM يُهدد التحقق من الكمال تمامًا — مع نفس المفتاح والNonce، يُكشف المفتاح المُستخدم للتحقق من الكمال (H). يمكن للغامض أن يُصنع مُدخلات تحقق من الكمال لنصوص مُشفّرة عشوائية. هذا ليس نظرية: الهجوم الممنوع يستخدم هذا ويُستخدم ضد تطبيقات حقيقية.
  • إعادة استخدام IV في CBC أقل تدميرًا لكنها سيئة — تصبح الهجمات المُختارة على النص المُدخل ممكنة. في الممارسة، يجب دائمًا توليد IV جديد لكل رسالة.
  • لا تُستخرج Nonce من محتوى الرسالة — المُدخلات المُحددة التي تعتمد على بيانات قابلة للتنبؤ تُنتج نمطًا متوقعًا. استخدم العشوائية.

عندما يكون CBC أو CTR هو الخيار الصحيح

لا يُعد GCM دائمًا الحل:

  • التوافق مع الأنظمة القديمة — إذا كنت تُدمج مع نظام يستخدم فقط AES-CBC، فإنك تستخدم CBC. اذكر بوضوح متطلبات التحقق من الكمال وقم بتنفيذها بشكل صحيح (تشفير ثم تحقق من الكمال باستخدام HMAC-SHA256).
  • البيئات المحدودة التي لا تحتوي على وحدة تسرع GHASH — خطوة التحقق من الكمال في GCM تستخدم GHASH، وهي عملية أكثر تعقيدًا من تشفير مُباشر على خوارزمية مُقسّمة في الأجهزة التي لا تحتوي على تسرع مخصص. قد تُبرر استخدام وضع CTR في بعض الأنظمة المُدمجة حيث لا تتوفر GHASH ولكن تتوفر CTR+CMAC.
  • تشفير التدفق لملفات كبيرة حيث تحتاج إلى تفكك مُمكن للوصول — خاصية الوصول العشوائي في CTR مفيدة عندما تحتاج إلى تفكك الموضع N دون قراءة المواقع من 0 إلى N-1. يسمح GCM تقنيًا بذلك، لكن التحقق من مُدخل التحقق من الكمال يتطلب معالجة كاملة للنص المُشفّر، مما يُهدد الهدف.
  • تشفير القرص — تشفير القرص الكامل يستخدم وضع XTS (غير مذكور هنا)، وليس GCM، لأن XTS مُصمم للقطاعات المُقاسة بشكل ثابت وقابل للوصول عشوائيًا. GCM مخصص للاستفادة من التشفير، وليس للاستفادة من تشفير القطاعات.

النسخة المختصرة

استخدم AES-256-GCM للكود الجديد. أعد توليد مُدخل عشوائي بحجم 12 بيت لكل عملية تشفير. أخزن المُدخل والمُدخل التحقق من الكمال مع التشفير المُشفّر. اعتبر فشل التحقق من الكمال كخطأ، وليس تحذيرًا — لا تُعيد النص المُفكّك عندما يُعلن أن البيانات غير صالحة في GCM.

إذا كنت تُراجع كودًا قديمًا يستخدم CBC: تحقق من أن "تشفير ثم تحقق من الكمال" مُنفّذ بشكل صحيح، تحقق من أن الـ IV عشوائية (لا تُعاد، لا تُسلسل)، وخطط لنقل إلى GCM عندما يسمح الوقت للصيانة. CBC مع تحقق من الكمال الصحيح ليس مُدمّر — هو فقط يحتوي على أكثر "أخطاء" من GCM.

ECB: استبدلها فقط. لا توجد مسارات تقييم تنتهي بـ "ECB مقبول هنا".

هل تريد حذف الإعلانات؟ تخلص من الإعلانات اليوم

تثبيت ملحقاتنا

أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع

أضف لـ إضافة كروم أضف لـ امتداد الحافة أضف لـ إضافة فايرفوكس أضف لـ ملحق الأوبرا

وصلت لوحة النتائج!

لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!

إعلان · حذف؟
إعلان · حذف؟
إعلان · حذف؟

ركن الأخبار مع أبرز التقنيات

شارك

ساعدنا على الاستمرار في تقديم أدوات مجانية قيمة

اشتري لي قهوة
إعلان · حذف؟