یک عدد جونیور علاقه مند به حوزه امنیت :)
رمزنگاری کاربردی - قسمت چهارم : Authenticated encryption
در فصل چهارم کتاب اقای وونگ میخوایم بریم سراغ بحث Authenticated encryption ؛ ولی قبل ادامه این مقاله رو از سری مقدماتی بخونید و حتما قسمت قبل یعنی Message authentication codes رو بخونید و بعد ادامه بدید XD
🔸مفهوم cipher رو از قبل باهاش آشنا هستید، در کتاب گفته شده که به encryption algorithms یا الگریتم های رمزنگاری میگن cipher
🔸4.2 The Advanced Encryption Standard (AES) block cipher
در 1997 یه مسابقه توسط NIST برگذار شد برای اینکه بهترین الگریتم(امن ترین) رو انتخاب کنن برای رمزنگاری متقارن و جایگزین DES بکننش، هر الگریتمی موفق میشد دووم بیاره، لقب AES میگرفت
🔸4.2.1 How much security does AES provide?
الگریتم AES چقد امنیت دارد؟ سه تا ورژن داریم، یکی AES-128 هست که یک کلید 128 بیتی میگیره(16 بایت)، یکی دیگه AES-192 که کلید 192 بیتی (یا 24 بایتی میگیره) و دیگری AES-256 هست که کلید 256 بیتی (یا 32 بایتی) میگیره
🔸نکته : هرچه طول کلید بیشتر، امنیت بیشتر (گنده تر=قوی تر)
اغلب از ورژن 128 بیتی استفاده میکنن چون 128 بیت امنیت حداقلی مارو تامین میکنه
(در کتاب اینطوری گفته شده : 128 bits of security) و bits of security اینجا ترجمه میشه به امن بودن الگریتم، یک اصطلاحه، میگن این الگریتم 128 بیت امنیت داره
🔸نکته ای که وجود داره اینه که اگر بخوایم بگیم هر primitive ای که 128 بیت امنیت به ما میداد، همیشه حداقل 128 بیت امنیت برای ما فراهم میکنه حرف غلطیه، فقط AES هست که اگر 128 بیتی شو انتخاب کنی حداقل 128 بیت امنیت داری و همونطور ک توی مقالات قبل خوندیم، بعضی مواقع مجبوری 256 بیت انتخاب کنی که 128 بیت امنیت داشته باشی !
🔸4.2.2 The interface of AES
الکریتم AES اول میاد یه ورودی کلید به طول معین (که بالاتر صحبت کردیم(3 نوع بود)) میگیره، و بعد یه PT به اندازه همون کلید میگیره و یه CT به اندازه همون کلید توی خروجی تحویل میده (ما به صورت خلاصه به PlainText میگیم PT و به CipherText میگیم CT)
چون توی AES ما یه مقدار ثابتی رو به عنوان PT میپذیریم و رمز میکنیم، به این الگریتم میگن block cipher و نوع های دیگه رو در ادامه میبینیم
🔸نکته: در رمزنگاری، primitive باید نتیجش و کاردکش و خروجی ثابت و قطعی باشه، نباید نتیجه کارش هربار متفاوت باشه ، این قانون بسیار مهم که تحت عنوان deterministic هست برای تمامی primitive ها صادقه، بجز اونایی که وظیفشون تولید مقادیر random هست
بخوایم توی کارکرد AES عمیق شیم به این میرسیم که block cipher ها (البته با کلید) هم جایگشتی کار میکنن،و این جایگشت توسط کلیدی که شما میدید تعیین میشه و این جایگشت معکوس پذیر هم هست (قابل بازگشت ) و اگر نبود decryption ای در کار نبود ...
🔸توی مقاله قبل یادتونه گفتیم ما یکی از اهدافمون تو رمزنگاری The pseudorandom function (PRF) هست؟ توی بحث cipher ها هم یکی از اهدافمون اینه که یه چیزی تولید کنیم که جایگشتی بسیار random داشته باشه ولی خب چون نیست به یه چیزی روی میاریم که "شِبهه جایگشت" باشه و اونم pseudorandom permutations (PRPs) هست، درواقع AES ها از جنس PRP ها هستن
🔸4.2.3 The internals of AES
بریم سراغ توضیح عناصر داخلی و نحوه کارکرد AES (فقط دقت کنید که خیلی وارد جزئیات نمیشیم) :
الگریتم AES میاد و PT مثل یک ماتریس 4در4 بایت میبینه، که چیز مهمیم نیست ولی خب طوریه که AES توی دنیای واقعی داره کار میکنه، AES یه تابع داخلیم داره به اسم round function که چندین بار ورودی رو از داخل این تابع رد میکنه و در نهایت به خروجی یا CT میرسه
وقتی که ما یه کلیدی برای AES تعیین میکنیم که باهاش رمز کنه، الگریتم میاد و از اون کلید اصلی چند تا کلید دیگه تولید میکنه و به این round function ها میده که باهاش اون PT مارو رمز کنن (درواقع به اندازه تعداد دفعاتی که از round function استفاده میکنه کلید تولید میکنه) و این کار در فرایندی تحت عنوان key schedule انجام میشه
واسه چی این کارو کردن؟ ما یه قانونی داریم تحت عنوان Diffusion که اگر تغییر کوچکی در PT یا key داده شد (حتی یک بیت) باید چندین بیت در CT تغییر ایجاد کنه (ما مثل همین رو توی Hash داشتیم ولی اونجا کل hash عوض میشد ولی اینجا کلش عوض نمیشه ولی تغییر چشمگیری داره)
داخل این round function چی هست ؟ توی این round function ها عملیات هایی انجام میشه (sub function هایی هست که این عملیات هارو انجام میده) و روی PT تغییرات ایجاد میکنن
اسمای این sub function ها به این صورته : SubBytes, ShiftRows, MixColumns, AddRoundKey
سه تای اول کار زیاد سختی نمیکنن و اگر عملیات به چهارمی نرسه، خیلی راحت میتونید از CT به PT برسید، ولی اصل کار رو چهارمی انجام میده که XOR انجام میده با round key و بعد این مرحله ما بدون کلید نمیتونیم از CT به PT برسیم
چند دور iteration با round function ها نیاز است ؟ مقادیر به این صورت هستن :
AES-128: 10 rounds | AES-192: 12 rounds | AES-256: 14 rounds
اگر شما تعداد دفعات استفاده از round function رو کم کنید، مثلا به 3 برسونید (مثلا برای AES-128)، حملاتی وجود دارند که بتونن کلید رو پیدا کنن (به این دسته از حملات میگن total breaks)
و اگر تعداد دفعات رو از حد پیشفرض بالا ببرید، واقعا امنیت بیشتری پیدا میکنن (شاید کُندی رو تجربه کنید) و کوچکترین تغییر توی PT باعث میشه ما یه CT بسیار متفاوت در خروجی ببینیم (قانون avalanche effect)
🔸فرق بین Diffusion و Avalanche Effect چیست؟ خیلی فرق خاصی ندارن و avalanche effect یجورایی زاده Diffusionو هست، یجورایی پیچیده شدش هست، ایده این بوده که اگر ما تغییری توی PT یا key بدیم نتیجه یا CT تغییر کنه (Diffusion) ولی امدن گفتن یه گزینه هم براشون بزاریم که شاید بخوان کلا CT رو عوض کنن، امدن گفتن خب avalanche effect رو میزاریم که همون کار Diffusion رو میکنه ولی خیلی شدید تر ! خیلی شدید تر !!!! (فک کنید یکی یه مشت میخوره و دماغش میشکنه، این میشه Diffusion ولی یکی انقد مشت میخوره که صورتش قابل شناسایی نیست، این میشه avalanche effect 😁)
اگر براتون سوال شده که چطوری میتونید بیشتر از 128 بیت دیتا رو رمزکنید، جلوتر بهش میرسیم
🔸4.3 The encrypted penguin and the CBC mode of operation
مشکلی که block cipher ها دارن اینه که بیشتر از سایز بلوکشون (مثلا 128 بیت در AES-128) نمیتونن PT ای رو قبول کنن ! برای اینکه بتونن مجبورن از padding به همراه mode of operation استفاده کنن؛
فرض کنید شما میخواید یه پیام بلند رو رمز کنید، میایید و به تیکه های 16 بایتی تقسیمش میکنید (به اندازه 128 بیت AES) و اگر بلوک اخری که باقی موند از 16 بایت کوچیکتر بود یه سری بایت بهش اضافه میکنیم که بشه 16 بیت، به این کار میگن padding
چندین روش هست که چگونه ما به padding خوبی برسیم منتها نکته مهم جریان اینه که این padding باید بازگشت پذیر باشه، یعنی وقتی CT رو رمزگشایی کردیم بتونیم قسمت padding شو تشخیص بدیم و حذفش کنیم؛ پس اگر مقادیر random بزنیم کار خراب میشه چون این مقدار random با PT قاطی میشه و قابل تشخیص نیست !
معروف ترین شیوه padding اسمش PKCS#7 padding هست و قاعدش اینطوریه که میاد میبینه طول اون بلوک باقی مونده (که کمتر از 16 بایته) چقدره و همون عدد رو برمیداره و به عنوان padding تکرارش میکنه
واسه حذف این padding هم میاید اخرین باید رو نگاه میکنید ( اخرین مربع سمت راست مثلا) و مقدارشو برمیدارید و به اندازه اون مقدار از PT کم میکنید (یعنی نگاه میکنید میبینید اخرین بایت نوشته 8، پس میایید از ته PT یه 8 تا بایت رو برمیدارید)
روشی که ما پیش گرفتیم نامش electronic codebook (ECB) هست و چون طبق قاعده deterministic باید هرباری که یه بلوک داده رو رمز میکنیم، به یه CT برسیم، یعنی اگر هر بلوک رو بخوایم جدا رمز کنیم، نتیجه یک الگوی تکرار شونده داره ! این الگوی تکرار شونده منجر به data leak میشه ! یعنی PT لیک میشه !
معروف ترین مثال، مثال عکس پنگوئن هست که مشاهده میکنید و تو سری مقدماتی هم توضیحش دادم
برای اینکه به این مشکل نخوریم باید بریم سراغ cipher block chaining (CBC) ، نحوه کارشم اینطوریه که یه initialization vector (IV) میگیره برای رندوم کردن رمزنگاری ، پس سایز IV به اندازه طول بلوکمون براورد میشه (یعنی 16 بایت) و باید random و تصادفی و غیر قابل پیش بینی باشه
پس ما 16 بایت IV میسازیم (اگر 192 یا 256 بیتی بود الگریتممون ، IV مون میشه به اندازه اون) و میاییم XOR اش میکنیم با PT (PT مون 16 بایتی) و این به صورت قابل توجهی خروجی رو تصادفی میکنه ! و PT های بیشترو (بلاک های بیشترو) بخوایم رمز کنیم ، از CT بلاک قبل به عنوان IV برای بلوک جدید استفاده میکنیم، اگر از همون IV ابتدایی استفاده کنیم ، CBC با ECB فرقی نمیکنه و همون میشه !
برای دیکریپت باید IV رو داشته باشیم، یعنی باید IV به صورت ClearText با CT به گیرنده فرستاده بشه و جفتش نیازه، چون IV قرار بوده تصادفی و random باشه پس حدس زدنی نیست؛ و ازش چیزی در نمیاد !
چیز هایی مثل IV توی رمزنگاری کامل درک و شناخته نمیشن و میتونن خودشون یه عامل برای به خطر انداختن Primitive باشن و باعث vullnerbility بشن؛ توی CBC ما IV رو طوری انتخاب میکنیم که هر بار خواستیم استفاده کنیم تکرار نشه ، و غیر قابل پیش بینی (غیر قابل حدس) باشه (خیلی تصادفی باشه)، و توسعه دهنده ها (developers) اگر بلد نباشن درست مقدار IV رو رندوم تولید کنن توی کدشون خیلی به مشکل میخورن ! سر همین یه سری کتابخونه های رمزنگاری این قدرت رو از کاربر میگیرن که IV رو بتونن مشخص کنن، و میاد IV رو خودش رندوم تولید میکنه !
🔸نکته : وقتی IV تکرار بشه (تکراری بشه)، پس CT هم تکراری میشه و قابل پیش بینی میشه ، یکی از حملات معروف توی این زمینه BEAST یا (Browser Exploit Against SSL/TLS) بود که روی TLS رخ میداد
🔸4.4 A lack of authenticity, hence AES-CBC-HMAC
توی سناریویی که باهم بررسی کردیم (رمزنگاری AES با حالت CBC) ما یه مشکلی داریم، اگر مهاجمی این وسط باشه و بیاد یه مقدار از IV رو تغییر بده چه اتفاقی می افته؟ درواقع ما اینجا مکانیزمی برای حفظ Integrity نداریم ! مهاجم اینجا میتونه IV رو تغییر بده و این نتیجه مستقیمی روی PT خروجی (در فرایند رمزگشایی) میزاره و خب شاید نتونه کار خیلی خطرناکی بکنه ولی ما پیامی که دریافت میکنیم خراب یا درهم میشه !
پس باید از یه مکانیزمی استفاده کنیم که جلوی این کارو بگیره (درواقع به ما هشدار بده که یه مهاجمی این کارو کرده، نه اینکه واقعا جلوشو بتونه بگیره)
اگر خاطرتون باشه ما HMAC رو داشتیم که ترکیب SHA-256 با MAC بود، ما میاییم MAC رو بعد padding کردن PT اعمال میکنیم، و از جفت CT و IV باهم ما استفاده میکنیم! درغیر این صورت مهاجم باز میتونه IV رو تغییر بده و کسی نفهمه !
ما میاییم از CT و IV باهم یه Authentication tag تهیه میکنیم و به همراه CT و IV میفرستیم به مخاطبمون ! اون با کلیدش Authentication tag رو باز میکنه و مطابقت میده با CT و IV ای که بدستش رسیده
🔸نکته : کاری که ما کردیم Encrypt-then-MAC هست، یعنی اول رمز کن بعد MAC رو بکار ببر، اگر از MAC-then-Encrypt یعنی برعکس این استفاده کنیم، مهاجم میتونه حمله padding oracle انجام بده که در سری حملات بهش میرسیم)
🔸 اسم این ساختار AES-CBC-HMAC هست ولی چون توسعه دهنده ها اشتباه پیادش میکنن و یا ازش استفاده میکنن، امنیت رو به اون صورت نمیتونه تضمین کنه ( مثلا تصادفی بودن IV رعایت نمیشه) و ما از این ساختار به ساختار جدید به اسم All-in-one constructions مهاجرت میکنیم (اگر حوصله کانفیگ IV شو ندارید و نکات رو رعایت نمیکنید بیخیال AES-CBC-HMAC بشید)
🔸4.5 All-in-one constructions: Authenticated encryption
بخاطر اینکه توسعه دهنده ها توی پیاده سازی و استفاده از authentication خیلی گند میزدن و حتی نمیتونستن کامل بفهمنش، تصمیم گرفته شد که برن سراغ یک ساختار کاملی که این کار رو برای توسعه دهنده ها راحت تر کنه ، دوتا ساختاری که قراره بررسی کنیم اسماشون AES-GCM و ChaCha20-Poly1305 هست
🔸4.5.1 What’s authenticated encryption with associated data (AEAD)?
امدیم یه چیزی ساختیم به اسم authenticated encryption with associated data (AEAD) که خیلی به AES-CBC-HMAC نزدیکه و تمام اون قابلیت هارو داره، بعلاوه که یه associated data هم داره که کمک میکنه به فرایند authentication ؛ این مقدار associated data یه مقدار optional و انتخابیه و میتونید خالیش بزارید یا هرچی که مایلید بزارید، بعضیا میان این مقدارو metadata مربوط به رمزنگاری و یا PT میزارن؛ این قسمت از داده رمز نمیشه و با CT منتقل میشه و یا ته CT میچسبوننش و منتقلش میکنن ، پس به طبع سایز CT بزرگتر از PT خواهد شد
برای رمزگشایی این CT ما به associated data نیاز داریم، اگر این مقدار دستکاری شده باشه ما نمیتونیم PT رو بازیابی کنیم و به ارور میخوریم، اگر اتفاقی نیفتاده باشه میتونیم به PT برسیم
برای مثال یه تیکه کد ببینید در زبان JS که از این روش استفاده میکنه؛ ما اینجا از Web Crypto API استفاده میکنیم که یک لایبرری یا کتابخونس که این قابلیت رو به ما میده که بتونیم اعمال سطح پایین یا low-level cryptographic داشته باشیم( یعنی خیلی قدرت به ما میده که تنظیمات رو دستکاری کنیم))
ما از AES-GCM اینجا استفاده کردیم، دقت کنید که در صورت استفاده از کتابخونه سطح پایین، احتمال اشتباه کردن توسعه دهنده به شدت بالاست !!
بهتون توصیه میکنم چون حجم زیادی رو تا اینجا خوندید و قراره حجم بیشتریم ببینید، حتما استراحت کنید و بعد ادامه بدید ;)
🔸4.5.2 The AES-GCM AEAD
پس تا اینجا فهمیدید که ما یه دسته بندی جدید داریم به اسم AEAD که دوتا نوع داره، اولین نوع این دسته بندی AES-GCM هست که دوتا قسمت داره: یک GMAC و یک Counter (CTR)
🔸از ChaCha20-Poly1305 و AES-GCM که دو نوع AHEAD ما هستن در رمزنگاری TLS استفاده میشه!
چون ساختار با AES یکی هست پس سرعت اون رو هم داره و از یک MAC خاص استفاده میکنه به اسم GMAC، ولی قبل بررسی GMAC بریم ببینیم CTR چطوری کار میکنه :
اولین قسمت یعنی AES-CTR میاد از یه nonce استفاده میکنه با یه عدد (که از 1 شروع میشه) بجای PT، این درواقع همون حکم IV رو داره ، و به ما این امکانو میده که خروجی تصافیی داشته باشیم ، بر خلاف IV خاصیت nonce اینه که تکراری نباشه ولی نباید غیر قابل پیش بینی باشه ! یعنی باید بشه پیش بینیش کرد! به بیانی دیگه باید منحصر به فرد باشه ولی رندوم نباید باشه؛ وقتی 16 بیت اولیه رمز شد ، نتیجیش میشه یه keystream که با PT میاد و XOR میشه و CT تولید میشه
🔸(درواقع وقتی nonce با عدد ما داخل AEAD میرن و رمز میشن با کلید، ما یه keystream داریم)
🔸اصلاح و کاربرد nonce دقیقا همون IV هست ولی پیش نیاز هاشون فرق داره، و nonce بر خلاف معنی ای که میده (معنیش تکرار نشونده است) ، باید تکرار بشه ! درواقع دستور العمل مشخص میکنه همه چیزو نه نام ها؛ و مد نظر داشته باشید که اگر nonce و IV رو بجای هم بکار ببرید اوکیه ولی توی پیش نیاز هاشون تفاوت هست !
مقدار nonce توی AES-CTR ثابته و 12 بایته، کلش 16 بایت بود پس میمونه 4 بایت که counter ما اونو پر میکنه و از عدد 1 هم شروع میشه و زیاد میشه، تا به مقدار 2به توان 32 منهای 1 یعنی 4,294,967,295 برسه، یعنی 4,294,967,295 بلوک از دیتا میتونه رمز بشه با یک nonce (کمتر از 69 گیگ)
اگر ما دوتا PT داشته باشیم بیاییم از یک nonce دو بار استفاده کنیم، keystream تکراری درست میشه و مهاجم میاد دوتا CT رو برمیداره و باهم XOR شون میکنه و اینطوری keystream هیچ کاری برای امنیت نمیتونه بکنه و مهاجم به مقدار XOR شده دوتا PT میرسه ، اگر مهاجم درباره یکی از PT ها چیزی بدونه که دیگه فاجعه رخ میده !
ما در AES-CTR چون به padding نیازی نداریم یه جورایی از Block cipher انگار رفتیم روی stream cipher و PT رو بایت به بایت رمز میکنیم!
یعنی اگر keystream بلند تر از PT بود، Truncate اش میکنیم تا به طول PT برسه ! اینطوری block cipher شد stream cipher
توی stream cipher ها ما مستقیما PT رو با کلید XOR میکنیم و نیاز به Padding و Mode of Operation نداریم، و PT و CT از لحاظ طولی اندازه هم درمیان :)
ما راحت میتونیم از block cipher بریم روی stream cipher اگر از CTR استفاده کنیم ولی فارغ از این مسئله از block cipher ها درکنار primitive های دیگه میشه استفاده کرد ولی stream cipher ها به این راحتی با primitive های دیگه مچ نمیشن.
🔸نکته : رمزنگاری طول PT تون رو مخفی نمیکنه ! و اگر شما قبل رمزنگاری بیایید و PT رو فشرده سازی کنید ! چون طول CT کوچیک میشه و کلید کوچیک تریم استفاده میشه امنیت بر فنا میره !
قبل ادامه حتما نکات پایانی قسمت hash رو بخونید، اونجا گفتم که ما یه نوع تابع هش داریم به نام یونیورسال که یه نوع ازش AUX هست (یه construction عه درواقع) و امدن یه تابع هش ساختن از روی AUX به اسم GHASH
قسمت دوم از AES-GCM هست که از GMAC استفاده میکنه که همون MAC عه ولی با GHASH ترکیب شده و بخاطر ویژگی های GHASH که توی مقاله دوم گفتم فوق العاده سریع تره و احتمال برخورد به collision ام براش خیلی کمه !
برای هش کردن با GHASH ما ورودی رو تیکه تیکه میکنیم (block) و حجمشم 16 بایت در نظر میگیریم و دقیقا مثل CBC میاییم هششون میکنیم و خروجی هم 16 بایت خواهد بود؛ و چون این هش به عنوان ورودی میاد و کلید میگیره ، به لحاظ تئوری مثل MAC عمل میکنه ، ولی ما یه محدودیتی داریم و اونم اینه که این one time mac هست، این یعنی از یه کلید نمیشه برای چند تا پیام استفاده کرد و اگر استفاده بشه و مهاجم بتونه mac یه پیامو یادبگیره، خیلی راحت میتونه بقیه پیامارو هم ببینه (چون همشون با یه کلید ساخته شدن) !!!!
پس ما میاییم از ساختار Wegman-Carter استفاده میکنیم (Wegman-Carter Construction) که به ما قابلیت تبدیل کردن این one time mac رو به many time mac میده، یعنی چی؟
توی این ساختار اول یه کلید master میسازیم که تصادفیه و بعد از روی اون یه سری tag میسازیم، یعنی با استفاده از pseudorandom function (PRF) یه لیستی از تگ ها میسازیم که پشت سر همن (sequencential) و این tag ها از این به بعد به عنوان کلید ما استفاده میشن، حالا GHASH رو با این تگ ها استفاده میکنیم !
دقت کنید که توی عکس بالا تلاش کردن این مورد رو نشون بدن ولی خب شاید شما فرقشو با عکس قبل (4.15) درک نکنید، اینجا کلید ها متفاوت هستن ! حالا میخوایم بریم سراغ CTR و ترکیبش با این :
اگر لازم بود حتما استراحت کنید و مرور کنید مطالب تا اینجارو، چون قراره یکم پیچیده تر بشه ;)
🔸نکته : اون nonce ای که توی CTR دربارش صحبت کردیم باید منحصر به فرد و تصادفی باشه وگر نه مهاجم میتونه راحت authentication key ای رو که GHASH ساخته رو بدست بیاره
و در نهایت میتونید AES-GCM رو ببینید که از ترکیب CTR و GMAC بدست امده (شبیه Encrypt-then-MAC عه که بالاتر در بارش گفتیم)
برای شروع counter از 1 شروع میشه ( 0 میمونه برای رمز کردن authentication tag ای که توسط GHASH ساخته میشه).
یادتونه توی AES-CTR یه کلید داشتیم (K) ؟ میان اونو با یک بلوک داده 128 بیتی تمام صفر که بهش میگن (all-zero block) رمز میکنن، خروجی این فرایند میشه یه کلید دیگه به اسم H که از این H برای رمز کردن در GHASH استفاده میکنن !
🔸نکته : ما یه 12 بایت nonce توی فرایند AES-CTR توی AES-GCM داشتیم ؟ یادتونه؟ این مقدار nonce باید منحصر به فرد باشه (unique) ولی اقای وونگ میگه لزوما نیاز نیست تصادقی با random باشه، و یه سری افراد از nonce به عنوان counter استفاده میکنن و باید اون کتابخونه (Library) شما به شما این اجازرو بده، و اگر این اجازرو بده شما میتونید دو به توان 12 ضربدر 8 منهای یکی پیام رو رمز کنید که خیلی مقدار زیادیه که شاید تو عمل اصلا به این مقدار از پیام نرسیم !!
حالا از طرفی اگر شما بخوایدcounter رو اینطوری خودتون مشخص کنید باید بدونید از کجا شروع کردید( مقدار اولیتون چقدر بوده که یکی یکی بهش اضافه کردید) و اگر کامپیوتر یهو این وسط crash کنه خب نمیدونید چی بوده و خیلی اوضاع خیت میشه ! سر همین یه سری از کتابخونه ها نمیزارن شما این مقدارو خودتون انتخاب کنید ، از طرفی با احتمال خیلی زیادی نمیزارن که مقدار nonce تولیدی و counter به تصادم بخوره (یعنی الگریتم ها اگر قرار باشه خودشون این هارو تولید کنن یه طوری تولید میکنن که در تعداد بالا باز شبیه هم نشن)
درسته که هرچه پیام بیشتر رمز بشه از nonce بیشتری استفاده میشه و ممکنه در تعداد پیام بالا یه collision ای رخ بده، پس بهتره بیشتر از دو به توان 30 تا پیام رو با یه کلید رمز نکنید، اگر از nonce تصادفی استفاده میکنید (به بیان ساده ، هر دو به توان 30 تا پیام یه بار کلیدو عوض کنید)
علی رغم اینکه تعداد دو به توان 30 پیام خیلی زیاده، و اگر یه سیستمی دائما درحال رمزکردن پیام باشه میتونه به محدودیت برسه، پس باید کلید رو عوض کنید برای این شرایط (تعویض کلید سر یه قاعده ای که اون قاعده تعداد پیام هاست یا زمان خاص) (جزئیات بیشتر تو عکس هست)
🔸4.5.3 ChaCha20-Poly1305
دومین AEAD ای که میخوایم دربارش صحبت کنیم ChaCha20-Poly130 هست، از ترکیب دو الگریتم ChaCha20 که stream cipher هست و Poly1305 MAC امده که هر دو این ها به صورت جدا توسط Daniel J. Bernstein طراحی شدن و گوگل هم توی 2013 امد استاندارد سازی کرد الگریتم Cha20-Poly1305 AEAD رو و تصمیم گرفت روی محصولات خودش از این استفاده کنه و پردازنده هایی با توان کم هم قابلیت استفاده از این رمزنگاری رو دارن ، بعلاوه توی خیلی از پروتوکل های امنیتی ازش استفاده میشه ، مثل OpenSSH، TLS و..
اقای Bernstein اول امد الگریتم Salsa20 رو ساخت و بعد امد ChaCha20 رو ساخت که جفتشونالگریتم stream cipher هستن، چطوری کار میکنن ؟ مثل تمامی الگریتم های stream cipher این ها میان و یه keystream تولید میکنن که حتما اندازه طول PT باید باشه، بعد با PT میان XOR اش میکنن که CT تولید کنن، برای decrypt شم همین الگریتم استفاده میشه که بیاد و keystream رو تولید کنه و XOR اش میکنن با CT که PT بدست بیاد
حالا ChaCha20 چطوری عمل میکنه ؟ میاد block function رو به تعداد دفعات بالا صدا میزنه که تعداد زیادی key stream 64 بیتی تولید کنه (64-byte blocks of keystream)؛ حالا این block function به عنوان ورودی چیا میگیره :
1 - یه کلید به طول 32 بایت (256 بیتی) (مثل AES-256)
2 - یه nonce به طول 12 بایت (92 بیتی) (مثل AES-GCM )
3 - یه counter به طول 4 بایت (32بیتی) (مثل AES-GCM )
و فرایند مثل AES-CTR میمونه ، داخل هر block function انقدر counter رو زیاد میکنیم که به اندازه نیازمون keystram داشته باشیم (نیازمون همون طول PTهست) ، اگر زیاد تر شد truncate اش میکنیم تا اندازه طول PT بشه، و در PT رو با کلید XOR میکنیم
🔸چون ما اینجا همون nonce ای رو داریم که توی AES-GCM داریم پس همون مقدار محدودیت هم داریم در استفاده از nonce و تعداد پیام هایی که میتونیم رمز کنیم ،ولی چون خروجی ای که این block function تولید میکنه بزرگتره ، میشه یه مقدار پیام های بیشتری رو رمز کرد :
🔸نکته : و مجدد اگر nonce تکرار بشه ، ما مشکلاتی که داشتیم در AES-GCM رو اینجا هم داریم.
(من اینو مجدد تکرار میکنم، چطوری مهاجم میتونه حمله بکنه ؟ دوتا CT ای ک داره رو باهم XOR بکنه و XOR شده دوتا PT رو بدست بیاره، اینطوری جلو بره ، حالا یا یکی از PT هارو داره یا از روی nonce بیاد authentication key رو بدست بیاره و..)
سایز nonce و counter همیشه یکسان نیست ولی مقادیر استانداری هست براشون ، ولی یه سری کتابخانه ها مقادیر متفاوتی از nonce رو قبول میکنن، و ی سری برنامه ها سایز counter یا nonce رو زیاد میکنن برای اینکه بتونن تعداد پیام بیشتری رو رمز کنن، ولی این افزایش سایز (هرکدوم ) منجر میشه به کاهش سایز اون یکی ! و در نتیجه مشکل امنیتی !
یه سری استاندارد ها مثل XChaCha20-Poly1305 هستن که تلاششون اینه که سایز nonce رو زیاد نگه دارن ولی سایز counter و ... تغییر نکنه ! و این ها کارا هستن مخصوصا در جاهایی که nonce باید تصادفی انتخاب بشه
داخل block function مربوط به ChaCha20 یه state داریم، که 16 تا کلمه میگیره و به شکل مربع به سایز 32 بایت هست، اولین خطش یه مقدار ثابت رو ذخیره میکنه ، خط دوم و سوم یه کلید متقارن 32 بایتی و خط اخر یه 4 بایت counter داریم و 12 بایت nonce ؛ حالا این state ما تبدیل میشه به 64 بایت keystream ، چطوری؟ توی round function میره این ورودی ها و 20 بار هم این کار تکرار میشه (بخاطر همینه که اسمش ChaCha20 هست) و دقیقا مکانیزمش مشابه AES هست
🔸نکته : ما توی ChaCha20 درواقع یه block function داریم که داخلش یه مکانیزمایی داریم به اسم round function که چندین بار تکرار میشن
این round function های داخل ChaCha20 ما خودشون "Quarter Round (QR) function" هستن که 4 بار روی هر round اعمال میشن (4 times per round) ، و نسبت به اینکه عدد round function زوج هست یا فرد میان و روی حروف مختلف state عملیات انجام میدن
این QR function ما 4 تا ارگومان مختلف میگیره و روی اونها سه تا عملیات انجام میده : (Add- Rotate -XOR) و ما به این cipher میگیم ARX stream cipher که بسیار سریعتر از بقیه cipher های دیگس و در عین حال پیاده سازیشم راحت تره !
حالا Poly1305 چیه ؟ یک MAC هست که بر اساس تکنیک Wegman-Carter ساخته شده دقیقا مثل GMAC که بالاتر گفتیم
یادتونه توی GMAC گفتیم چطوری one time mac میشه many times mac ؟ اینجا روش فرق داره ولی هدف و رویکرد همونه؛ ما توی poly1305 دوتا جزء داریم ؟
یه r داریم که دقیقا مشابه H ماست توی GMAC، و یه مقدار ثابتیه که برای تمامی پیام هایی که با یه کلید رمز میشن ثابت میمونه
و یه s داریم که بر خلاف k توی GMAC ، یه مقدار منحصر به فرده که برای هر پیام جدا ساخته میشه و یه جورایی میتونید nonce تصورش کنید که هم جلوی replay attacks رو میگیره هم باعث میشه integrity اون mac ما حفظ بشه
فرایند اینطوریه که : اول کلید ما (r) میاد با accumulator میکس میکنه که مقدار اولیش هم 0 هست (پایین تر توضیح میدم چیه ولی فرض کنید تا اینجا که یه ظرفه)، فرایند ریاضیش اینطوریه که بلوک داده با کلید (r) ضرب میشه و باقی ماندش بر یک عدد اول(P) ذخیره میشه ، همیطور میره جلو
🔸منظور از accumulator توی Poly1305 چیه؟ فرض کنید یه پیام داریم که تقسیمش کردیم به سه قسمت مساوی 16 بایتی ، پس سه تا block داریم، block 1 ، block 2 ، block 3 :
اول Accumulator = 0 هست
برایBlock 1 ما این فرایندو داریم : Accumulator = (Accumulator * r) + Block 1 (mod P)
برای block 2 این فرایندو داریم : Accumulator = (Accumulator * r) + Block 2 (mod P)
برای block 3 این فرایندو داریم : Accumulator = (Accumulator * r) + Block 3 (mod P)
برای هر block ما مقدار Accumulator اولیمون فرق داره، برای اولی 0 هست، برای دومی 1 ، برای سومی 2 و..
امید وارم هم فرمول رو دقیق تر فهمیده باشید هم منظور از Accumulator رو
🔸نکته : جزئیات زیادی این وسط نادیده گرفته شده مثل نحوه encode کردن دیتا، یا پدینگ ارگومان ها قبل پاس دادنشون و... که جزئیات زیادیه و دوست داشتید سرچ کنید (اینو آقای وونگ میگه نه من)
پس در نهایت ما از ChaCha20 و یه counter با مقدار صفر استفاده میکنیم برای ساخت keystream و یه16 بایت r و 16بایت هم s در میاریم برای Poly1305 و در نهایت میرسیم به الگریتم ChaCha20-Poly1305 :
از ChaCha20 برای ساخت r و s استفاده میشه که مایحتاج Poly1305 هست، counter یکی بهش اضافه میشه هر بار و با ChaCha20 میاییم و PT رو رمز میکنیم، بعد اون assosciated data و CT (و طولشون)رو پاس میدیم به Poly1305 برای ساخت Authetication tag
قبل رمزگشایی هم اول ChaCha20 میاد صحت CT و associated data رو بررسی میکنه و بعد رمزگشایی میکنه
🔸4.6 Other kinds of symmetric encryption
پس ما تا اینجا این هارو یادگرفتیم :
- Non-authenticated encryption :
این میشه AES با یه mode of operation بدون MAC ، و چون CT رو میتونن جعل کنن خطریه !
- Authenticated encryption :
این شامل AES-GCM و ChaCha20-Poly1305 میشه که جفتی دوتا cipher مورد قبول و قوین
🔸سایر الگریتم های متقارن که وقتی AES-GCM و ChaCha20-Poly1305 ناکارامد هستند به درد میخورند :
🔸4.6.1 Key wrapping
یکی از مشکلات الگریتم های AEAD ای که متکی هستن به nonce اینه که متکی هستن به nonce 😂
این nonce فضای بیشتری میگیره ، و وقتی شما یه PT رو با کلید رمز میکنید لزوما نیاز به randomize کردن ندارید ، حالا NIST امده یه استاندارد زده به اسم
800-38F: “Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping.”
این الگریتم های key wrapping از nonce یا IV استفاده نمیکنن و خودشون تو ساختارشون random سازی رو دارن
پس عملا چیز اضافه ای ب اسم nonce یا IV ندارن :)
🔸4.6.2 Nonce misuse-resistant authenticated encryption
در سال 2006 یه نفر به اسم Phillip Rogaway امد یه الگریتم key wrapping ابداع کرد به اسم synthetic initialization vector (SIV) که هم برای رمز کردن کلید ها بدرد میخورد هم به عنوان AEAD چون مشکلات تکرار nonce رو نداره !
همونطور که تاحالا یادگرفتید اگر nonce تکرار بشه چه توی AES-GCM و یا ChaCha20-Poly1305 میتونه ختم به جاهای بسیار خطرناکی بشه... نه تنها XOR دوتا PT رو میتونه لو بده بلکه میشه authentication key هم دراورد و حتی encryption رو هم forge کرد و...
نکته الگریتم مقاوم به تکرار اشتباهی نانس( nonce misuse-resistant algorithm ) که ایشون درست کرده اینه که اگر شما دوتا PT یکسان رو با یه nonce رمز کنی، دقیقا یکسان میشن، در غیر اینصورت اصلا یکسان نمیشن ! حالا چطوری nonce رو میسازه؟ این الگریتم از روی PT میاد و nonce رو میسازه، سر همون اصلا امکان نداره که با این الگریتم ، ما با nonce ها به مشکل بخوریم !
اسم استانداردشم اینه :
RFC 8452: “AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption.”
🔸4.6.3 Disk encryption
برای رمز کردن حافظه چه توی موبایل چه کامپیوتر و ... ما چالش های زیادی داریم، مخصوصا سرعت و اینکه حجم دیتای خروجی یا همون CT نباید بیشتر از PT بشه ، پس سر همین استفاده از authenticated encryption algorithms ها خط میخوره چون اون ها این قابلیت هارو ندارن (nonces و authentication tags حجم میدن به دیتا) و باید بریم سراغ الگریتم های قدیمی که اول مقاله معرفی کردیم، ولی اونا هم یه مشکلی دارن، دسخوش یه حمله میشن به اسم bit-flip که مهاجم میتونه بیت هایی از CT رو تغییر بده و PT خروجی هم به طبع تغییر میکنه (توی سری حملات رمزنگاری بررسیش میکنیم)
امدن گفتن ما بجای اینکه دیتا هارو block block کوچیک رمز کنیم بیاییم کلشو یه block در نظر بگیریم (یعنی یه حجم زیادی از دیتارو یه block در نظر بگیریم) و یجا باهم رمز کنیم که هم جلوی حمله bit-flip رو بگیریم هم کند نباشه، امدن wide-block ciphers رو ساختن که چندین هزار بایت رو باهم میگیره و یکجا رمز میکنه ، حالا مشکلی که اینجا هست اینه که اگر مهاجم دست به bit-flip بزنه ممکنه کل دیتارو غیرقابل خواندن کنه و خراب کنه ولی نمیتونه دیگه پی به دیتا ببره یا چیزیو عوض کنه ! فقط میتونه خرابش کنه؛ و این خوبه :)) به این روش poor man’s authentication هم میگن و با اینکه authentication نداره ولی احتمال حمله رو هم به مهاجم نمیده
در لینوکس و دستگاه های اندرویدی از Adiantum استفاده میشه که یه wide-block construction هست که از روی ChaCha ساخته شده ولی Microsoft و Apple کلا رفتن سمت AES-XTS که میشه (XEX-based tweaked-codebook mode with ciphertext stealing) و نه authentication ای رو بهمون میده و نه wide-block عه، پس چیه ؟ چیز پیچیده ای نیست و اتفاقا به bit-flip هم اسیب پذیره ! یکم جلوتر بیشتر بازش میکنم
🔸4.6.4 Database encryption
رمز کردن یه دیتابیس خیلی سخته چون نمیشه همشو رمز کرد، دارن باهاش کار میکنن و برای فهمیدنش کلید میخوان و اگر کلیدم بدی خب چه فایده ای داره رمز کردنش؟ کلید باید توی یه سرور دیگه ذخیره بشه ، حالا اگر بخوایم رمز کنیم یکار کنیم؟ از transparent data encryption (TDE) استفاده میکنیم که یه سری ستون های خاص رو رمز میکنه فقط؛ حالا نکته اینه که کسی که میخواد رمز کنه باید حواسش به associated data هم باشه و row و column نظرشم رمز کنه وگر ن دیتا راحت میتونه swapped یا جابجا بشه
یعنی چی این یه قسمت که گفتم ؟ اول بگم که associated data یعنی متادیتای دیتابیس، یعنی RowID و Colum id ، حالا چرا رمز کردن اینا مهمه ؟ فرض کنید ما دوتا ستون داریم به اسم name و address و اگر شما ستون address رو رمز کنی و associated data رو رمز نکنی ، یه مهاجم میتونه ادرس دوتا سطر رو جابجا بکنه و شما متوجه نشی
یه سری جزئیات دیگه هم اقای وونگ گفته که من انگلیسیشو میزارم اگر خواستید بخونید :
🔸AES-XTS (XEX-based tweaked-codebook mode with ciphertext stealing) :
این رو لازم دونستم قبل اتمام خودم یه مختصری راجبش بگم چون کتاب اقای وونگ چیزی نگفته بود: این الگریتم برای رمزکردن فضای ذخیره سازی استفاده میشه مثل ssd-hdd و یا sd card ها و... و یه سری ضعف های ECB رو نداره ودر کل خیلی خوبه؛ از طرفی XTS به tweakable اشاره میکنه که معنی لغویش میشه "قابل تنظیم" و این قابلیت یعنی بتونیم فرایند رمزنگاری هر بلوک داده رو تغییر بدیم، یعنی رمز کردن هر بلوک وابستس به موقعیتش توی اون جا (index اش کجاش مثلا)، و این جلوی یه سری حملات مثل اینو میگیره : identical plaintext blocks producing identical ciphertext blocks
و در AES-XTS از دو تا کلید جدا استفاده میشه ، یکی برای رمزنگاری خود دیتا و دیگری برای ساخت tweak و این ساختار چرا خوبه؟ چون اگر یکی از کلیدا لو بره ، مهاجم نمیتونه بدون داشتن کلید دوم به PT برسه
یه قابلیت جالبی که AES-XTS داره ciphertext stealing هست که بهش اجازه میده بلوک های داده متفاوتی رو رمز کنه، حتی بدون padding !
عما توی AES-XTS ما authentication نداریم، و از طرفی این الگریتم مثل سایر AES های دیگه به bit-flip اسیب پذیره؛ و اگر authentication نباشه و یا جلوی حمله bit-flip گرفته نشه ، مهاجم با دست بردن توی CT میتونه توی PT خروجی تغییر ایجاد کنه و یا خرابش کنه !
ماکروسافت از AES-XTS برای رمزنگاری داخل ویندوز استفاده میکنه ، حدس میتونید بزنید چه ابزاری؟ bitlocker :))
اپل هم برای macOS خودش از AES-XTS استفاده میکنه ، توی ؟ FileVault
این الگریتم خیلی سریعه ، مخصوصا از سخت افزار هم ازش ساپورت کنه!
خلاصه این فصل :
فصل چهارمم تموم شد، فصل بعدی سراغ مبحث Key exchanges میریم (و کلی مباحث ریاضی :)) )
امید وارم براتون مفید بوده باشه
منتظر سوالات، انتقاد و پیشنهاداتتون هستم
یاعلی ;)
مطلبی دیگر از این انتشارات
رمزنگاری کاربردی - قسمت سوم : Message authentication codes
مطلبی دیگر از این انتشارات
رمزنگاری کاربردی - قسمت اول : مقدمات
مطلبی دیگر از این انتشارات
رمزنگاری کاربردی - قسمت دوم : Hash Function