رمزنگاری کاربردی - قسمت دوم : Hash Function

در فصل دوم از کتاب اقای دیوید وونگ به بحث Hash Function میرسیم ، اولاش هش رو توضیح داده که ازش میگذریم ولی حتما قبل ادامه این مقاله رو از سر مقدماتی بخونید

🔸اصطلاحات مربوط به خروجی یا ouput یک الگریتم Hashing:

به خروجی الگریتم هش اصطلاحا میگن "دایجست" "digest" یا "هش" "hash" ، این ها تخصصین، ولی بعضیا check-sum یا sum هم میگن که غیر تخصصیه و بهتره از همون دایجست استفاده کنیم

🔸 چه خروجی هایی برای یک digest مناسب هستند؟

یه قسمت از کتاب اشاره به این داره که ما دیتای باینری رو نمیتونیم همینطوری نمایش بدیم ، چون اولا خراب میشه و شما کپیش کنی اصلا دیتا از بین میره، دوما کاراکتر های نا معلوم برای این کار نمایش داده میشه، پس یا باید 0 و 1 نمایش بدیم (مبنای دو یا base2) که خیلی بلند میشه متنش! یا باید تبدیلش کنیم به مبنای دیگه ای، اینجا از مبنای 16 یا base16 یا همون هگزادسیمال نام میبره و میگه که میشه ازش استفاده کرد ، و base32 و base64، خود کتاب گفته هرچقد بیایید بالاتر و مبنای بزرگتری انتخاب کنید طول خروجیتون کمتر میشه !

(کتاب میگه اگر مثلا از مبنای 16 استفاده کنید ، بجای هر 8 بیت میاد دوتا کاراکتر استفاده میکنه (8->2) یعنی اگر 100 بیت رو ما بخوایم با هگز تبدیل کنیم با 25 تا حرف کارمون راه میفته ! یعنی 4 برابر حجم کمتر !)

🔸 اصطلاحات پیرامون ویژگی های هش ها :

از سری مقدماتی اگر یادتون باشه من به 4 تا نکته درمورد هش اشاره کردم، تو 4 امی گفتم نباید دوتا مقدار متفاوت رو اگر ازشون هش گرفتیم به یه خروجی برسیم، اسم علمی این second preimage resistance هست ! و توی کتاب به این مفهوم اشاره شده ، یه مفهوم دیگم بود که هش نباید برگشت پذیر باشه (مورد اولی) و این قابلیت اسم علمیش pre-image resistance هست

🔸 محدودیت در ورودی یک الگریتم موجب ضعف آن است :

الگریتم رمزنگاری یا هشینگ اگر توی ورودی گرفتن محدودیت داشته باشه، خیلی راحت میشه موارد محتمل رو پیش بینی کرد و امنیت رو دور زد (مثالش هش lm قدیمی ویندوز که تا ویندوز ویستا بود و پسورد زیر 15 کاراکتر رو نال میکرد و میشد راحت فهمید و حدسش زد) پس اگر توی رمزنگاری چیزی قابل پیش بینی باشه یا حجم ورودیش کم باشه امنیت نداره !

🔸 تفاوت بین Collision Resistance و Second Preimage Resistance چیه؟

هر دو یک مکانیزمی ان که که براش هش هستند و نمیزارن که شما دوتا ورودی پیدا کنی که به یک هش یا دایجست برسه، ولی فرقشون چیه ؟

کتاب در تعریف Second preimage resistance میگه اگر من به شما یه input بدم و یه digest نظیرش که با یه الگریتمی هش شده ، شما نباید بتونید یه input دیگه پیدا کنید که اگر ازش هش بگیرید به digest قبلی برسید

در تعریف Collision resistance ولی میگه که این قابلیت تضمین میکنه که هیچکس نباید بتونه دوتا مقدار input بسازه که وقتی هشش میکنید به یه digest ختم بشه

خب تا اینجا کلی گیج شدید، ولی بزارید تفاوتشونو توضیح بدم (کتاب نوشته خودتون برید بفهمید😂)

درواقع تفاوت توی آزادی عملیه که مهاجم داره، در Collision Resistance مهاجم میتونه دوتا input دلخواه انتخاب کنه ولی در Second preimage resistance به مهاجم یه ورودی و دایجست نذیرشو دادن و گفتن یه مقدار پیدا کن که وقتی hash گرفتی ازش به همین digest برسی

🔸 توضیح بحث random oracle :

یه موضوعی رو اینجا اقای وونگ خیلی گنگ مطرح میکنه، اونم بحث random oracle هست: فرض کنید ما یه جعبه سیاه داریم که اگر هر مقداری توش بدید یه مقدار رندوم و غیر قابل حدس بهتون برمیگردونه، این جعبه اسمش random oracle هست، حالا رمزنگاری ها و کسایی که میخوان پروتوکل رمزنگاری یا هش (مخصوصا هش) طراحی کنند، از یه random oracle استفاده میکنن به عنوان یه الگویی که از روش الگریتم و تابع هش رو بسازن ، درواقع از روش میخوان بسازن (و با استفاده از این random oracle ها که به عنوان نقشه هستند ، دیگه لازم نیست زیاد نگران این باشیم که output رندوم باشه)

درواقع خیلی تمثیل مسخره ایه ولی فکر کنید شما میخواهید خونه بسازید و بیایید از یه مایع بسیار سخت و سفت استفاده کنید و روی اون خونتون رو ببرید بالا، وقتی در دنیای واقعی میخواید خونرو بسازید از اجر استفاده میکنید و خب همون کاراییو داره دیگه :) درواقع random oracle یه ابزار تئوریه و الگریتم و توابع هشی که در دنیای واقعی ساخته میشن دوست دارن خیلی بهش نزدیک باشن و اگر شد مثل اون بشن، دقیقا مثل نقشه ساختمون که قراره خونه یه طور خاصی ساخته شه ولی توی زمان اجرا باز تفاوت های محسوس و نا محسوسی پیدا میکنه

🔸 حمله تاریخ تولد و بحث Collision الگریتم هاش Hashing :

کتاب مفهوم collison و حمله تاریخ تولد رو میگه که من در سری مقدماتی گفتمش ، ولی به صورت خلاصه توی یه اتاق اگر 23 نفر باشن به احتمال 50 درصد تاریخ تولد دوتای اون (هرکدوم) یکیه ! و همینطور توی رمزنگاری اگر ما الگریتم 128 بیتی داشته باشیم باید 2 به توان 128 تا بیت تولید کنیم (خروجی) که collision در بیاد، و نصف این مقدار یعنی 2 به توان 64 تا اگر تولید کنیم به احتمال 50 درصد collision خواهیم داشت

🔸 بررسی مفهوم Truncating :

بررسی مفهوم Truncating در الگریتم های Hashing : گاهی اوقات توسعه دهنده ها یا developer باید از الگریتم sha256 مثلا استفاده کنه ولی میخواد حجم خروجی رو کمتر کنه ، خب چیکار میکنه؟ میاد تو کد از sha256 استفاده میکنه ولی وقتی خروجی کد رو گرفت ، میاد و اونو نصف میکنه و از نصف اون digest استفاده میکنه (یعنی انگار از الگریتم 128 بیتی استفاده کرده بجای 256) و این کار به شدت خطرناکه !!!

اگر میخواهید به امنیت 128 بیتی برسید باید از الگریتم 256 بیتی استفاده کنید، چرا؟ (طبق عکس بالا) اگر 2 به توان 128 بیت تست بشه به احتمال 50 درصد محتوا شما decrypt میشه، و حالا به صورت علمی (به شرط استفاده نکردن از Truncation) : برای دستیابی به امنیت 128 بیتی از یه الگریتم 256 بیتی استفاده کنید برای اینکه 256 بیت مناسب Collision Resistance هست و نصفش یا 128 بیتش مناسب second pre-image resistance هست

🔸 کاربرد های Hashing در دنیای واقعی :

1- در سایت هایی که میرید برای دانلود یک فایل حتما دیدید که بعضیاشون یه hash بغل اون لینک دانلود گذاشتن و این برای اینه که وقتی شما یه فایل رو دانلود میکنید بعدش از فایل هش بگیرید و اگر تغییر کرده بود متوجه بشید که فایل اصلی نبوده و یکی این وسط فایل رو تغییر داده !

(کتاب میگه این هش به راحتی میتونه توسط صاحبای وبسایت عوض بشه ، پس ما برای اطمینان به سایت به امضای دیجیتال و اینا نیاز داریم ، که خب شما میدونید اینو :) HTTPS نباشه کار خرابه )

2- فرض کنید قراره انتخابات ریاست جمهوری آمریکا اتفاق بیفته و شما از قبلش از نتیجه خبر دارید، و میخواهید وقتی نتیجه ها معلوم شد به دوستتون اثبات کنید که خبر داشتید ولی الان نمیتونید چیزی به اون بگید، چطوری این کارو انجام میدید؟ شاید روی یک کاغذ بنویسید و در جایی قرار دهید، ولی روش بهترش استفاده از الگریتم هش هست، مثلا جمله Trump is the next president رو هش میکنید و مقدارش رو به دوستتون میدید، بعد انتخابات اگر دوستتون یا شما بیایید همین مقدار رو به الگریتم بدید، دقیقا همون هش رو برمیگردونه !

شما با الگریتم های هش تقریبا میتونید به دوتا هدف برسید :

hiding : شما میتونید محتوایی ک میخواید رو مخفی کنید

binding : شما نمیتوانید بعدا انکار کنید که محتوایی که مخفی کردید چیز دیگری بوده

و یکی از گزینه هایی که برای سناریو بالا میتونید استفاده کنید ، استفاده از هش هست (قطعا شما با رمزنگاری متقارن و نامتقارن میرید جلو ولی خب فرض کنیم اینجا نه !)

3- استفاده برای Subresource integrity : اغلب وبسایت ها میان و کتابخانه یا فایل های java script مورد نیازشونو روی CDN های مختلف سرتاسر جهان میزارن و خب خودشونم میرن روی CDN ، وقتی درخواست میاد سمت سایت، سرور میره از CDN اون فایل js رو میخونه، خب اگر تصور کنیم CDN یبار بخواد کار خرابی کنه و این فایل رو آلوده کنه چی پیش میاد؟ یکی از کاربر های هش در همین مواقعه، کنار تگی که ادرس فایل JS هست میان هش اون رو هم میزارن ، وقتی مرورگر شما یه صفحه ای رو لود میکنه میره از اون لینک فایل js رو دانلود میکنه و هش میگیره ازش، اگر هش با چیزی که سایت بهش داده منطبق نبود اخطار میده !

دقت کنید که هر الگریتمی اولش نوشته باشه باهمون میره هش میگیره !

استفاده از قابلیت فوق در کلودفلر
استفاده از قابلیت فوق در کلودفلر

4- شبکه تورنت (BitTorrent) : یوزر ها (در شبکه تورنت به یوزر میگن peer) با تورنت میان فایل به اشتراک میزارن بین خودشون به صورت مستقیم (بدون واسط یا peer to peer) ، برای به اشتراک گذاری میان فایل رو قسمت قسمت میکنن و هر قسمت رو جدا ازش hash میگیرن ، این هش ها بعدا به عنوان یه چیزی که نشون میده فایل معتبره استفاده میشه. برای مثال magnet link پایین فایل ubuntu v19 هست که در قالب هگزادسیمال نمایش داده شده و درواقع هش متادیتا فایل و تکه تکه های فایله

magnet:?xt=urn:btih:b7b0fbab74a85d4ac170662c645982a862826455

5- شبکه tor : توی ویرگول درباره TOR نوشتم اگر نمیدونید چیه از اینجا بخویندش، توی TOR شما میتونید hidden site بسازید و امینت شما وقتی شما وصل میشید به این سایتا توسط پروتوکلی تامین میشه که از کلید عمومی (Public Key) اون صفحه استفاده میکنه (شما میخواید وصل بشید به یه سایت TOR ، اون سایت یه کلید عمومی داره، مرورگر میاد از این کلید عمومی برای امن کردن ارتباط شما با اون سایت استفاده میکنه)؛ یک گروهی بودن به اسم Silk Road که مواد میفروختن توی TOR و توسط FBI دستگیر شدن، اسم سایتشون این بود : silkroad6ownowfk.onion و این اسم عجیب و غریب درواقع هش کلید عمومی Silk Road هاست (البته در مبنای base32) ، پس اگر شما آدرس .onion رو بدونید میتونید از کلید عمومی اون سایت اطمینان حاصل کنید و مطمئن شید دارید با کسی که میخواید حرف میزنید

باید بدونید که اگر hash درست و امن گرفته نشه به راحتی قابل تعویض و جعله و لزوم داریم با یه کدی قاطیش کنیم که این مشکل پیش نیاد و اونم message authentication code هست، این مورد رو توی سری مقدماتی توضیح دادم ولی فصل سوم این کتاب به این مسئله مفصل پرداخته.

🔸2.5 Standardized hash functions

کتاب میگه یه سری به اصطلاح الگریتم های Hashing مثل CRC32 اصلا الگریتم هشینگ نیستن و بیشتر برای مسائلی مثل error checking استفاده میشه ، حالا چرا؟ چون اصلا اون 4 تا ویژگی ای ک گفتیم رو ندارن ! همچنین الگریتم هایی مثل SHA-1 یا MD5 با اینکه هنوزم استفاده میشن ولی چون براشون حمله کشف شده و قدرت کامپیوتر ها هم برای حل این ها بالا رفته، دیگه استفاده نمیشن و نباید ازشون استفاده کرد

🔸2.5.1 The SHA-2 hash function

میخوایم بریم سراغ بررسی الگریتم SHA2 و نگاه کلی به نحوه کارکرد این ها داشته باشیم، چرا کلی؟ اگر یادتون باشه بالاتر گفتم ما random oracle و جعبه سیاه داریم؟ نمیشه کامل گفت چطوری عمل میکنه ! الگریتم SHA2 توسط NSA ابداع شدو و توسط NIST هم در 2001 استاندارد سازی شد

قبل ادامه حتما قسمت سوم سری مقدماتی رو بخونید ، مفاهیم اونجارو توی کتاب اورده ولی من نمیارم و اگر بلد نباشید نمیفهمید !!!

ما کارمونو با یه تابع به اسم compression function شروع میکنیم، اسمش تابع فشرده سازیه، دوتا ورودی میگیره که سایز هردوشونم باید یکسان باشه و خروجی ایم که میده به همون سایزه (مثلا اگر دوتا 4 بایت بگیره یه 4 بایت میده)

الگریتم SHA2 برای ساخت compression function از روشی به اسم Davies–Meyer استفاده میکنه (هرچند روش های دیگه ایم هست) که مبتنیه بر block cipher (که شما میدونید چیه ولی مجدد میگم که برای رمز کردن مقدار معین (FIX) از دیتاست)، ساختار الگریتم SHA2 اسمش هست Merkle–Damgård که میاد و به صورت مکرر اون compression function رو صدا میزنه

چون compression function ما یه مقدار ثابت رو بیشتر نمیتونه به عنوان ورودی بگیره، باید بیاییم و ورودی رو یه کاری کنیم که بشه چند قسمت مساویش کرد، مثلا compression function ما 8 بایت ورودی میگیره و ما 27 بایت ورودی داریم، اینجا میاییم 0 به ته اون 27 اضافه میکنیم، 5 تا 0 اضافه میکنیم و میشه 32 بایت، حالا 32 ای که داریم رو اگر تقسیم بر 8 کنیم میشه 4 تا، عالی !

به عملیاتی که 0 به ته مقدار ورودی اضافه میکنیم میگن Padding

حالا میاییم این 4 تا 8 بایت رو به ترتیب داخل این compression function ها میکنیم و خروجی compression function قبلی میشه ورودی جدید

نکته :درواقع compression function دوتا ورودی میگیره، یکی اون 8 بایتی که گفتم و یکی یه IV که میشه که از جذر 8 عداد اول استفاده میکنه ، عدد خاصیم نیست و جامعه امنیتم اینطوری مطمئنن که Backdoor ای درکار نیست، برای توابع دوم تا اخر ما برای IV از خروجی compression function قبلی استفاده میکنیم)

نکته : ساختار Merkle–Damgård دربرابر Collision مقاوم است اگر خود اون تابع compression function ما هم مقاوم باشد، بنابر این ما چطوری امنیت یک ورودی با طول دلخواه رو تضمین میکنیم؟ به واسطه استفاده از compression function که طول ثابتی داره، این نبوغ ساختار Merkle–Damgård است :)

نکته : الگریتم SHA2 درسته که امنه ولی به حمله ای ب اسم lengthextension attack آسیب پذیره که بعدا درموردش صحبت میکنیم.

🔸2.5.2 The SHA-3 hash function

الگریتم SHA-1 و MD5 هردو بر اساس ساختار Merkle–Damgård بنا شده و SHA2 هم که length-extension attacks ،در سال 2007 NIST امد مسابقه برگذار کرد برای الگریتم SHA3 و الگریتم SHA3 اختصاص یافت به Keccak و تا 2017 دیگه رسمی به نامش ثبت شد؛ الگریتم SHA3 به اندازه SHA2 و تمام انواعش امنیت داره و به length-extension attacks هم اسیب پذیر نیست

شما مجموعه ای از عناصر را در سمت چپ و راست دارید، از هر کدوم از عناصر فقط میتونه یک فلش ازش شروع بشه و بهش ختم بشه ، حالا شما جایگشت دارید.و طبق تعریف هر جایگشتی نیز برگشت پذیر است، یعنی میتوانیم از خروجی ورودی را پیدا کنیم (این ویژگی جایگشته نه Hash، قاطی نکنید باهم !)

الگریتم SHA3 با ساختاری به نام ساختار اسفنجی (sponge) کار میکند که متفاوت از Merkle–Damgård است ، اسم جایگشت الگریتم keccak-f هست که یک ورودی مییگرد و یک خروجی با همان اندازه برمیگرداند (به همان اندازه رو دقت کنید)

(مدرس گفته درمورد keccak-f در فصل 4 صحبت میکنه چون عملکردش با AES شبیه (فقط کلید نداره) و کسی که AES رو ساخته کسی بوده که SHA3 رو ساخته)

نویسنده از یک مثال برای نشون دادن نحوه کارکرد جایگشت 8 بیتی استفاده میکنه :

این اعداد باینری همون شکل مثلث و دایره و ستاره و.. بالا هستند و شما میتونید جای اون هارو با عدد عوض کنید، مثلا 000 میشه مثلث یا 100 میشه مربع و..

(یک اشکال بالارو با دقت نگاه کنید، نیازی نیست حتما ستاره به ستاره وصل شود و دایره نیز به دایره وصل شود، میتواند وصل شود میتواند به چیز دیگری وصل شود، این رو حتما مطمئن شید که درک کردید)

برای اینکه بتونیم از جایگشت استفاده کنیم باید یک تقسیم دلخواه ورودی و خروجی ره به نرخ و ظرفیت تعریف کنیم (درسته گیج شدید ولی جلوتر براتون شفاف میشه)، جایی که ما حد بین نرخ (rate) و ظرفیت (capacity) را تعریف میکنیم دلخواه است، مقادیر مختلف SHA3 از پارامتر های متفاوتی استفاده میکنند. و باید بدونید که ظرفیت باید محرمانه بماند و هرچقدر هم بزرگتر استفاده شود، امنیت الگریتم نیز بیشتر خواهد بود !!

براش هش کردن ما فقط XOR میکنیم مقدار ورودی یا Input رو با rate یا نسبتی که گفتم بهتون، و چون capacity قرار بود یه مقدار محرمانه بماند پس طبیعتا هیچ کاری باهاش نداریم و هیچ کاری باهاش نمیکنیم.

همونطور که میبینید ما یه لیست 0 داریم و قسمتی rate شو با یه مقدار01 میاییم و XOR میکنیم و به قسمت capacity هیچ کاری نداریم .

خروجی به دست امده اکنون باید تصادفی باشد (چرا؟ اولا که ما با یه قسمتی به نام rate فقط XOR کردیم و بعد جایگشت انجام میشه !) ولی میشه فهمید که ورودی کدوم بوده چون جایگشت برگشت پذیر است (هنوز کامل الگریتم هش نساختیم! حواستون باشه)

اگر بخواهیم ورودی بزرگتری را وارد کنیم چی میشه؟ مشابه SHA-2 میاییم این کار هارو میکنیم :

1 - یا ورودی را Pad میکنیم و ورودی را به بلو هایی به اندازه rate تقسیم میکنیم

2 - به طور مکرر جایگشت را صدا میزنیم در حینی که داریم بلوک هارو باهم XOR میکنیم (درواقع اولش ورودی رو با یه قسمت از دیتا و جایگشت XOR میکنیم، بعد خروجی شو با یه قسمت دیگه از دیتا و جایگشت XOR میکنیم و به همین ترتیب ..)

در عکس 2.15 میبینیم که روش دوم رو پیش گرفته و میگه که ما مکرر XOR کنیم خروجی جایگشت قبلی رو با جایگشت بعدی

چون ساختار اسفنجی است (اسفنج رو دیدید که وقتی اب رو میخواد جذب کنه چقد باد میکنه و وقتی دفع میخواد بکنه چقد کوچیک میشه؟ جذب رو بهش میگیم "جذب" یا absorbing و دفع آب رو بهش میگیم "هضم" یا squeezing) درواقع در مرحله absorbing ورودی بهش میدیم و در مرحله squeezing اون به ما digest میده. این اسفنج با جایگشت 1600 بیتی با استفاده از مقادیر مختلف برای r و c فرق میکند و امنیت متنوعی رو تضمین میکند

(منظور از 1600 بیت جایگشت مقدار ورودی و خروجی هشه، یعنی 1600 بیت میگیره و 1600 بیت برمیگردونه، ولی خب چون c فرق میکنه ما امنیتمون فرق میکنه)

(دقت کنید که درسته جایگشت 1600 بیته و من گفتم ورودی 1600 بیت میگیره و خروجی 1600 بیت میده، ولی گفتم که ورودی اگر طولش زیاد بود قسمت قسمت میشه، ولی ورودی حتما 1600 بیته)

پس اگر ورودی میتونه متغییر باشه و خروجی 1600 ثابته چطوری مقادیر مختلفی از هش SHA3 داریم؟ 128 بیت 256 بیت و.. ؟ تعداد دفعات جایگشت برای هر کدوم فرق داره ، و خروجی ای که تولید میشه truncate میشه که بتونه به تعداد بیتی که براش معین کردید برسه

(این c هیچ ربطی به خروجی بیتی الگریتم نداره ها! یعنی نیایید بگید c رو اگر بتونم بیشتر بگیرم مثلا الگریتم میشه 128 بیت یا 256 بیت !!! اینطوری نیست !! هرچند شما هم نمیتونید مستقیم بهش دسترسی داشته باشید ! )

🔸نویسنده اشاره میکنه که الگریتم SHA3 خیلی شبیه Random oracle هست و از این منظر که خیلی رندومه ، خیلی مناسبه !

🔸2.5.3 SHAKE and cSHAKE: Two extendable output functions (XOF)

تا حالا الگریتم SHA-2 and SHA-3 رو دیدیم که ورودی دلخواه میگرفت و خروجی ثابت میداد ، ولی ما میخوایم که علاوه بر اینکه ورودی ثابتی نمیدیم، خروجی ثابتی هم نگیریم ! و در عین حال امنیتم داشته باشیم

برای این منظور استاندارد SHA-3 یک primitive دیگه به اسم XOF یا extendable output function (با تلفظ زُف) معرفی کرد که چند کاره بود

ما دوتا XOF استاندارد شده داریم به اسم SHAKE and cSHAKE :

🔸SHAKE :

یک تابع برای هش گرفتنه (با SHA3 میاد و جدا نیستن از هم) و خروجی دلخواه بهتون میدن ، ساختار SHAKE با SHA3 یکیه فقط یکی سریعتره و دوم هرچقد بخواید جایگشت انجام میده (توی مرحله squeezing)
این خروجی دلخواه (با امنیت، نه مثل truncating) برای بحث هایی مثل ساخت کلید رندوم یا مباحث دیگه ای توی رمزنگاری خیلی کاربرد داره که بعدا بهش میرسیم

🔸cSHAKE :

یک سال بعدی که SHAKE استاندارد سازی شد، NIST خیلی ذوق زده شد و امد نسخه قابل تغییر SHAKE رو داد با نام customizable SHAKE یا cSHAKE و دقیقا شبیه SHAKE هست با این تفاوت که یه string هم میگیره ، حالا یا میتونید هیچی ندید یا هرچی دلتون خواست بدید (یاد salt افتادید نه؟ مکانیزم همونه :) )

میبینید که دوتا digest باهم فرق دارن و با توجه به اینکه متن ورودی و طولش یکیه ! فقط custom string فرق داره !

کاربرد این مثلا کجاست؟ توی یه سری جاها برای اینکه یه مسئله رو ثابت کنیم باید از چندین الگریتم hash استفاده کنیم، این کاربردش اونجاهاست

بخدا اگر بدون دانش اولیه کتابو بخونید هیچی نمیفهمید :)

آقای وونگ به مفهوم domian seperation اشاره میکنه، مفهوم خیلی سادست

شنیدید میگن همه تخم مرغاتونو توی یه سبد نذارید؟ اینم همونه ، این قانون میگه اگر شما یه طلا داری، یه دلار و یه سکه، توی صندوق های مختلفی بزارشون؛ کاربردش تو رمزنگاری میشه که شما اگر میخوای از یه پیام و یه رمز هش بگیری، با یه الگریتم این کارو نکن و از دو الگریتم حتما استفاده کن، اینطوری هم سردرگرمی نداریم و دیتاها قاطی نمیشه و هم مهاجم اگر بتونه یکی رو بشکنه برای اون یکی دردسر داره

🔸قانون domain separation یک قانون طلایی و کلی در رمزنگاری هست که طبق گفته اقای وونگ در عکس بالا اگر مثلا میخواید از یه primitive استفاده کنید در دوجا، حتما کلیداشو متفاوت انتخاب کنید یا یه تغییری کلا توش بدید !

🔸bit attack :

مفهوم bit attack از جایی میاد که شما بین بیت و بایت تفاوت قائل نشی و جابجا ازشون استفاده کنی، یه جا گفته 12 بایت خروجی میدم، تو بکنیش 12 بیت مثلا ! اینجا فاجعه اتفاق می افته !

NIST عزیز خیلی اصرار داره که با بیت کار کنید ولی خب خیلیا با بایت کار میکنن و این بده

همیشه حواستون باشه که با چه واحدی کار میکنه !

🔸و حواستونم باشه که مثل هر چیز دیگه ای توی رمزنگاری، طول استرینگ ها مثل کلید ها یا پارامتر ها و حتی output ها به شدت به امنیت سیستم وابستس، به زبان ساده یعنی هرچی سیستم قوی تر => طول رشته خروجی بیشتر

یعنی اگر شما از الگریتم 256 بیتی استفاده کنی امنیتت خیلی تضمین تره و احتمال حمله بهت خیلی کمتره تا 128 بیت !

🔸2.5.4 TupleHash :

الگریتم TupleHash برای هش کردن یک لیست از ورودی هاست و بر مبتای cSHAKE هست، بریم سراغ داستان:

روزی روزگاری به نویسنده ما یک پروژه محول میشه که باید یک سیستم cryptocurrency طراحی کنه که کار های اولیه رو انجام بده مثل حسابداری ، ثبت مبالغ و .. ، حتی transaction هایی که توشون متادیتاهایی دارن که کی چه مبلغی رو به کی انتقال داده یا حتی هزینه ناچیزی که برای انتقال و استفاده از شبکه شما پرداخت میکنید

فرض کنید alice میخواد transaction شو توی شبکه ارسال کنه و باید اثبات کنه که خودشه، خب میتونه از هش استفاده کنه و امضاش کنه، و همه میتونن از transaction آلیس ما هش بگیرن و اعتبار سنجیش کنن، حالا اگر یه مهاجمی این وسط بخواد یه مقداری رو تغییر بده چون hash عوض میشه لو میره و بخاطر second pre-image resistance نمیتونه یه مقدار دیگه پیدا کنه که با hash آلیس یک مقدار باشه و خب شکست میخوره

اقای وونگ میگه طوری که من سیستم رو پیاده سازی کردم ، اینطوری بوده :

$ echo -n "Alice""Bob""100""15" | openssl dgst -sha3-256
34d6b397c7f2e8a303fc8e39d283771c0397dad74cef08376e27483efc29bb02

بنظرتون عالیه؟ شاید ولی افتضاحه

چرا؟ یک دقیقه فکر کنید که چه transaction دیگه ای هست که اگر ازش hash بگیریم به همین digest برسیم؟

شما اگر یک عدد از fee کم کنید و به قیمت اضافه کنید باز هش همونه :)

$ echo -n "Alice""Bob""1001""5" | openssl dgst -sha3-256
34d6b397c7f2e8a303fc8e39d283771c0397dad74cef08376e27483efc29bb02

این دقیقا مشکلیه که TupleHash رفع کرده، میاد غیر مبهم هش میگیره و هر کدوم از مقادیر اگر جاشون عوض بشه مثل مثال بالا ، کامل digest عوض میشه

در اینجا دو نکته خیلی مهمه (دنباله همن درواقع) :

1- Prefixing with Length : ما در هش اگر بخوایم از مقادیری هش بگیریم به صورت لیستی (مثل روش بالا) باید معلوم کنیم هر مقدار طولش چقدره، که نتونن طول مقادیرو جابجا کنن و هش تغییری نکنه ! یعنی اگر طول معین باشه خیلی از مشکلات ، مخصوصا مشکلات امنیتی پیش نمیاد

اگر طول مشخص نباشه امکان داره یه تغییری توی یکدوم از مقادیر بده و چون طول رو براش تعیین نکردیم ، بتونه مقدار خودشو معرفی کنه و هش هم تغییری نکنه (فرض کنید میخواید توی مثال crypto بالا، مبلغ 15 دلار در شبکه وارد بشه و ازش بخواد هش گرفته بشه، اگر طول براش تعیین نکنیم، یکی میتونه بیاد بگه 15000 دلار بوده !!!)

2- Serialization : این فرایند میاد و دیتاهایی که استراکچر و قالب دارن رو خطی و یکدست میکنه و این خیلی کار رو راحت میکنه برای پردازش اون دیتا ، ذخیرش و..

اقای وونگ میگه قبل اینکه هش بگیرید یک لیست رو باید مقادیرش رو ثابت کنیم و serialize کنیم دیتامون رو

🔸2.6 Hashing passwords

بحث ذخیره پسورد ها سمت وب هست که چیز جدیدی نیست براتون و توی سری مقدماتی توضیحش دادم

ولی چند تا نکته داشت :

یه سری الگریتم های غیر استاندارد مثل bcrypt و PBKDF2 و scrypt خیلی در دنیای واقعی استفاده میشن که اگر پارامتر های نا امن بهشون داده بشه خیلی نا ایمن میشن ! (مثلا شما تعداد iteration رو کم انتخاب کنید یا از مقادیر salt کوتاه استفاده کنید و...)

الگریتم های password storage دو نوع هستن : یا میان و روی محاسبات زوم میکنن و هزینه محاسبات رو زیاد میگیرن (یعنی محاسبات و CPU-GPU بیشتری مطلبن) و Memory کمتری میگیرن، یا از اون طرف محاسبات رو ساده میگیرن و Memory رو بیشتر میخوان

الگریتم های bcrypt و PBKDF2 نوع اول هستن و این کجا مشکل ایجاد میکنه؟ اگر شما بخواید این هارو کرک کنید فقط نیازه که سخت افزار قوی بندازید و با پیشرفت تکنولوژی و افزایش قدرت محاسباتی CPU-GPU ها این ها به راحتی کرک میشن

ولی الگریتم هایی مثل Argon2 و scrypt نوع دوم هستن، یعنی حافظه به شدت بالایی میخوان برای محاسبه (حافظه cache نه ram) و این گزینه سرعت کرک اون هارو به شدت میاره پایین

اصطلاحا به الگریتم های نوع دوم که به حافظه بیشتری نیاز دارن memory-hard functions میگن

خلاصه فصل فوق
خلاصه فصل فوق


نکات اضافه :

همونطور که توی سری مقدماتی قول داده بودم قراره یک سری مباحث رو اینجا اضافه کنم که پیشرفته تر باشه

توی بحث آنالیز بد افزار ما فقط از هش های عادی نمیتونیم استفاده کنیم ، چرا؟ چون فرق کنید اگر اون نویسنده بدافزار بیاد یه کلمه یا یک بیت از اون بدافزارو تغییر بده، هش کاملا عوض میشه ولی بدافزار همونه !

امدن یه مدل هش معرفی کردن به اسم Fuzzy Hashing که میاد فایل رو به چند قسمت تقسیم میکنه و از هر قسمت جدا هش میگیره، با این مکانیزم اگر کد بدافزار عوض شده باشه بازم بهمون میگه !

برای مقایسه دوتا بدافزار میاد هرکدومو به چندین قسمت تقسیم میکنه و از هر کدوم جدا هش میگیره و مطابقت میده، و میگه چند درصد تطابق داره و چند درصد نه !

دوتا هش دیگه هم هست به اسم Section Hashing و Import Hashing که برای دونستنش باید مفاهیم PE رو بلد باشید، سر همین فعلا نمیتونم اینجا بازش کنم

بررسی مفهوم Universal Hash Functions :

متاسفانه آقای وونگ توی فصل 4 ام از این مبحث استفاده کرده ولی توضیحی دربارش نداده، برای درک بهتر اون فصل بهتره این متنو بخونید، هرچند بدون دونستن این هم میتونید مفاهیمو بفهمید

هش های یونیورسال (جهانی ترجمش نمیشه ‌کرد😂) برای این تولید شدن که در جاهایی که randomization صورت میگیره نقش ایفا کنن (بدرد جاهایی که چیز تصادفی تولید کنن میخوره) و این هش های یونیورسال مثل هش های معمولی ، تلاششون بر اینه که برای دوتا ورودی مجازی، هش خروجیشون نزدیک به هم نباشه

یعنی اگر شما دوتا ورودی متفاوت دادی ، مثل هش های معمولی باید سعی بکنن هش یکسانی تولید نکنن و خروجی جفتشون متفاوت باشه

خب خسته نباشید، فرقشون چیه؟😂 بزارید اول فرمولشو ببینیم باهم :

یک عدد اول p

یک کلید k رندوم که از این رنج انتخاب بشه [1,p−1]

ورودی ما x هست و تابع هش ما Hk(X) هست:

Hk(X)=(k×X) mod p

(اینکه میگیم یک عدد بین 1 تا 1-p منظور اینه که اگر ما عدد 5 که اول هست رو در نظر بگیریم، رنج اعدادمون 1 تا 4 میشه)

کل امنیت این الگریتم هش به p و k ای هست که انتخاب میکنیم، و اگر دوتا مقدار رو باهاش هش کنیم : Hk(X) و Hk(Y) این دوتا خروجی متفاوتی خواهند داشت

خصوصیات این الگریتم های یونیورسال چیه ؟

1- هش های یونیورسال بر خلاف هش های معمولی قطعی نیستند(بر اساس عدد p انتخابی ممکنه جواب هربار عوض بشه)

2- در هش های یونیروسال احتمال برخورد به collision توی این هش ها به p و k تون ربط داره

3- هش های یونروسال از عبارات تصادفی استفاده میکنن ولی هش های معمولی نه

4- هش های یونیورسال برای فراهم کردن امنیت ساخته نشدند ! ولی هش های معمولی چرا

5- هش های یونیورسال بسیار سریعتر و راحت المحاسبه ترن 😂

هش های یونیورسال برای این ساخته شدند که ما از قابلیت الگریتم های هشینگ قدیمی استفاده کنیم ولی خروجی ثابتی نداشته باشیم، این ها وقتی به کار میان که با MAC ترکیب بشن و یا جایی که نیاز به RANDOMNESS داشته باشیم

یکی از معروف ترین هش های یونیورسال AXU هست یا Almost XOR Universal که ترجمش میشه هش یونیورسال تقریبا XOR شده ! ما از روی AUX امدیم یه تابع هش ساختیم به اسم GHASH ،توی فصل 4 ام بهش نیاز داریم :)

🔸نکته : یکی از اسمای AUX اینه : difference unpredictable function (DUF)

نکته : در ادامه مدرس یه تکنیکی میگه که من اینجا یه مثال میزنم ولی در مقاله های بعدی به وفور ازشون استفاده میکنیم، گاهی اوقات ما دوتا (CT(CipherText داریم، و میخوایم به مقادیر اولیشون پی ببریم! میاییم این دوتارو در هم XOR میکنیم، شاید شما فکر کنید که کار پیچیده شده ولی خیر ! اینطوری انگار ما دوتا PlainText یا متن اولیشون رو توی هم XOR کردیم، حالا اگر یکی از اون متن هارو ما داشته باشیم میتونیم متن دیگه رو هم در بیاریم !

حالا توی زمینه hash هم جریان همینه ، اگر دوتا مقدارر ورودی متفاوت داشته باشیم وهاشونو باهم XOR بکنیم و جواب بشه 0 (معنیش میشه collsion داریم) یعنی دوتاشون یکیه ! ولی اگر نشه 0 یعنی یکی نیست و متفاوته !

hk(x)⊕hk(y)=0

عبارت بالا یعنی ما collision داریم و الگریتم هش ما برای دوتا ورودی متفاوت یک خروجی یکسان تولید کرده

کرک پسورد:

برای کرک پسورد و کلا کرک تمامی Primitive ها ما میریم روی سیپیو های بسیار حرفه ای

شما برای کرک باید یا خیلی پولدار باشید و یه سیپیو AMD Threadripper بخرید که خیلی گرونه :)) و باید برنامه ای بنویسید که Parallel شروع به کرک کنه

یا برید سراغ سایت هایی مثل linode یا هر کلود پروایدری که دوست دارید و یه سرور ساعتی بگیرید با ۱۰۰ ها هسته سیپیو یا گرافیک و شروع به کرک کنید ؛)


فصل دوم تموم شد، فصل بعدی سراغ مبحث Message Authentication Codes میریم

امید وارم براتون مفید بوده باشه

منتظر سوالات، انتقاد و پیشنهاداتتون هستم

یاعلی ;)