• 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
رمزنگاری متقارن حرفه ای در PHP
#1
خب بیشتر از چیزی که فکر میکردم کار داشت، اما بالاخره آماده شد.

این آخرین تکامل کدهای رمزنگاری بنده هست یعنی در حد ناسا و سازمان امنیت ملی آمریکا :biggrin:

الگوریتم مورد استفاده: AES-128 (CBC) + HMAC-SHA256

این کدها هم شامل الگوریتم رمزگذاری هست و هم الگوریتم رندوم امنیتی (که میشه جداگانه در کاربردهای دیگری هم ازش استفاده کرد). الگوریتم رمزگذاری ما برای کارکرد خودش نیازمند تابع رندوم امنیتی ما است.

این کدها از نظر علم رمزنگاری خیلی حرفه ای و با حساسیت بالایی در زمینهء امنیت هستن، بطوریکه فکر نمیکنم تاحالا کسی در ایران مشابهش رو نوشته باشه و حتی در اینترنت هم کدها و روشی که اینقدر از نظر استانداردهای امنیتی کامل باشه بنظرم خیلی به سختی میشه پیدا کرد. ولی این کدها به همین خاطر خیلی هم حجیم هستن و مسلما نسبتا به نمونه های مبتدی و غیرحرفه ای پردازش خیلی بیشتری طلب میکنن و بنابراین ممکنه در کاربردهایی که مدام به عملیات رمزنگاری به تعداد خیلی زیادی نیاز هست با مشکل پرفورمنس مواجه بشید، ولی بهرحال من اینا رو اول برای کاربرد و برنامه های خودم نوشته بودم که چنین شرایط و نیازهایی نداشتن و در عمل مشکلی هم مشاهده نکردم. فکر میکنم برای خیلی افراد دیگر هم چنین شرایط و مشکلی وجود نداشته باشه، اما اگر وجود داشت اونوقت باید دید چه میشه کرد و یکسری بهینه سازیهای قابل توجهی فکر میکنم روی همین کدها هم میشه داشت، اما خیلی وقتا هم مجبوریم مقداری از حساسیت روی امنیت کم کنیم تا بتونیم پرفورمنس رو افزایش زیادی بدیم. بهرحال قصد بنده ساختن یک چیزی کم و بیش بی نقص از نظر امنیت و اصول علم رمزنگاری حرفه ای بود و پرفورمنس رو لحاظ نکردم. در بعضی موارد حتی از حدی که استانداردها تعیین کردن هم فراتر رفتم، ولی این کار از روی مدتها تحقیق و دانش و بینش بوده و نه نظر شخصی. حتی استانداردهای رسمی هم لزوما بی نقص و بهترین نیستن!
ولی در عین حال احتمالا حتی روی همین کدها هم میشه باز حساسیت بیشتر و بهبود و افزایش امنیت به لحاظ تئوریک رو داشت!! اما من شخصا دیگه حالش رو نداشتم بیش از این مته به خشخاش بذارم. شاید برای نسل بعدی بازم بهبودش بدم :wink:


البته این کدها رو یک مقدار سردستی و چون اول برای کار شخصی خودم نوشته بودم، از نظر متد کدنویسی و این حرفا زیاد تمیز و اصولی نیست.

خب روش استفاده از این برنامه خیلی ساده است.
در فایل test.php ما یک رشته ای رو رمز کردیم و بعد رمزگشایی کردیم و نمایش دادیم. خیلی ساده و روشن است و فکر نمیکنم نیاز خاصی به توضیحات بیشتری باشه!
راستی mt_rand رو فقط برای این استفاده کردم که رشتهء ما هر بار تغییر کنه که این توی مرورگر برای فهمیدن کارکرد برنامه مفیده و از یکسری اشتباهات و دردسرها جلوگیری میکنه، وگرنه نیازی به این تابع در اونجا نیست و کاربردش فقط برای کمک به تست برنامه است.
و اما یک نکتهء مهم کلید رمزگذاری ماست!
دقت کنید بنده از چنین کلیدی استفاده کردم:
کد:
$KEY='k#bbU-Tq!==gc4*hal3%@}';
این الان طولش و نوع کاراکترهاش روی حسابه و همینطور کشکی و دلخواه نیست!
شما کلیدی که تعیین میکنید باید تعداد حالت های ممکن اون رو حساب کنید که حداقل 2 به توان 128 باشه (بیشتر شد اشکالی نداره و بی تاثیره، ولی کمتر نباشه).
توجه داشته باشید که امنیت رمزنگاری شما هیچوقت از قدرت کلید شما بیشتر نمیشه. پس کلید خیلی مهمه.
البته کلیدی که من گذاشتم اگر دقیق حساب کنیم تعداد حالتهاش از 2 به توان 128 هم خیلی بیشتر میشه، ولی با توجه به اینکه این کلید توسط انسان انتخاب بشه و کلیدهای انتخاب شده توسط انسان کیفیت پایینی دارن (مثلا احتمال استفاده از یکسری کاراکترهای خاص توسط انسان خیلی بیشتره و یکسری دیگر خیلی کمتر)، فکر میکنم جانب احتیاط رو گرفتم. اما میشه کلید رو توسط همون تابع رندوم امنیتی بنده هم تولید کرد و به این شکل بیشتر میشه مطمئن بود. بطور مثال ما اگر علامتهای خاص رو هم نذاریم، و فقط اعداد و حروف بزرگ و کوچک به تنهایی و رشته ای به طول 22 کاراکتر، و چون هر کاراکتر میتونه از بین 62 کاراکتر انتخاب بشه، بنابراین تعداد حالتهای ممکن برای رشتهء ما میشه 62 به توان 22 که از 2 به توان 128 هم مقداری بیشتره؛ اگر طول رشته رو 21 کاراکتر میگرفتیم، تعداد حالتهای ممکن از 2 به توان 128 کمی کمتر میشد، به همین خاطر بنده جانب احتیاط رو گرفتم و میگم طول 22 کاراکتر باشه.

راستی شاید بپرسید چرا ما از AES256 استفاده نکردیم. جواب اینه که چون بنده بعنوان یک آدم مطلع و متخصص بعد از سالها اینو فهمیدم که وقتی میگن AES256 بیشتر تبلیغات هست و جنبهء روانی داره تا اینکه در عمل و از دید تخصصی اهمیت و مبنای واقعی داشته باشه، چون AES128 برای تمام کاربردهای عادی امنیت کافی داره (اغلب خیلی بیشتر هم از حد کافی) و AES256 مقداری هم کندتره (فکر کنم حدود 40%). اما گفتم که امنیت مثل زنجیره که ضعیف ترین حلقهء اون پاره میشه و به این شکل کل زنجیر از هم میپاشه، حکایت رمزنگاری هم همینه و فکر نمیکنم در کل ایران بشه برنامه نویس و برنامه ای پیدا کرد که برنامه هاش اونقدر امن و اصولی باشه که انتخاب بین AES128 یا AES256 براش مسئلهء براستی سرنوشت سازی باشه! در 99.9999% موارد ایرادها و حفره ها و ضعف های بزرگتری در جاهای دیگری پیدا میشه. ولی اگر شما میخواید مثلا اسناد فوق محرمانهء امنیت ملی رو رمزگذاری کنید، یعنی چیزهایی که ممکنه مثلا سازمان سیا و کشورهای قدرتمند و پیشرفتهء دنیا بخوان رمز اونها رو بشکنن، در این صورت باید حساس تر بود و بیشتر روی این مسئله تامل کرد! بهرحال هر چیزی حدی داره، برای هرچیزی حدی تعیین میشه که صرف کنه و نامعقول نباشه، همین کدها هم که من نوشتم شاید برای 99.99% برنامه ها و اطلاعات خیلی بیشتر از حد نیاز هم باشه، بخصوص که برنامه نویسان و برنامه های واقعا قوی و حرفه ای و بی نقص در زمینهء امنیت بسیار بسیار کم هستند. من برای کاربردهای خودم هم دنبال بیشتر از این امنیت نبودم و نیستم چون واقعگرایانه نیست، ولی زمانی اگر شرایط خاص و درجهء امنیتی خیلی بالا باشه، فرض مثلا میخوایم اسنادی رو رمز کنیم و میخوایم تاجاییکه میتونیم تلاش کنیم تا امنیت اونها حتی تا 50 سال دیگر هم برقرار باشه، اونوقت باید اصولا طرح و برنامهء جدیدی رو شروع کنیم و بنظر بنده صرفا استفاده از AES256 هم کافی نیست و باید تمهیدات پیشرفته تری رو هم بهش اضافه کنیم.

البته در پایان فراموش نکنید که هیچوقت نمیشه امنیت رو 100% تضمین کرد! هیچوقت! مثلا ممکنه همین فردا اعلام کنن که الگوریتم AES شکسته شد! کی میدونه؟ کی میتونه تضمین بده؟ تازه غیر از این خیلی احتمالات دیگر هم هست، ولی خب ما چیزی خیلی بیشتر از این و تضمین بالاتری از این الگوریتم ها و امکانات سراغ نداریم. خوشبختانه تجربه سالیان نشون میده که الگوریتم هایی مثل RSA و AES الگوریتم های خوبی هستن که شاید حتی تا ده ها سال دیگر هم امن بمونن. شاید حتی تا 100 ها سال! شاید برای همیشه! کسی نمیدونه. الگوریتم های رمزنگاری اکثرا اثبات های کامل و قطعی ریاضی ندارن، ولی در عین ها ریاضیات در اونها خیلی مهم و پرکاربرده و اثبات هایی با پیشفرض های ثابت نشده ولی با احتمال درستی قابل توجه وجود دارن.
علم امنیت و رمزنگاری بسیار گسترده و پیچیده است، و اکثر افراد از این قضیه بی اطلاع هستن و دست کم میگیرن!
هیچوقت قطعیت و تضمین کامل وجود نداره، صدها احتمال و پارامتر خطرساز وجود داره، ولی دریایی دانش و جزییات و ابزار و اطلاعات و تجربیات هم در این زمینه وجود داره که اگر دانسته و رعایت بشه میشه به بالاترین درجات امنیت ممکن دست پیدا کرد، و در غیر این صورت احتمال دست یابی به توهم امنیت بسیار بیشتره!


فایل‌های پیوست
.zip   crypto.zip (اندازه 22.72 KB / تعداد دانلود: 10)
  پاسخ
تشکر شده توسط :
#2
دلیلی داشته با mcrypt استفاده نکردی؟ فرقی چیزی داره؟
  پاسخ
تشکر شده توسط :
#3
(۱۳۹۵ بهمن ۰۷, ۰۱:۳۱ ق.ظ)admin نوشته: دلیلی داشته با mcrypt استفاده نکردی؟ فرقی چیزی داره؟
منظورت کجاشه؟
من از یک کلاس AES/Rijndael و مخلفاتش استفاده کردم که کس دیگه نوشته، البته یکسری تغییرات دادم و چندتا تابع بهش اضافه کردم و بنظرم یکسری ضعف هایی داشت که بهبود دادم (مثلا تابع رندومش ضعیف بود). حالا توی اون کلاس AES ظاهرا از mcrypt در صورت وجود در محیط استفاده میکنه، وگرنه از پیاده سازی خودش در PHP، یا شاید هم نه، کلاسش خیلی حجیمه و شاخ و برگ زیاد داره منم هیچوقت کامل نخوندمش!
این کلاس رو چندین سال پیش برداشتم که اون زمان نسخه ها و هاست های پی اچ پی قدیمی تر بودن و mcrypt شاید روی خیلی هاشون بصورت پیشفرض در دسترس نبود، بخاطر همین این بهترین گزینه بود.

اما از یک جهت دیگه، AES خودش در عمل برای امنیت الگوریتم کاملی نیست و فقط بخش encrypt یا تخصصی تر و درست تر بگیم همون بحث confidentiality رو انجام میده، و مثلا برای integrity/authentication چیزی نداره و باید خودت یک MAC بهش اضافه کنی. البته مدهای جدیدتری بعدا طراحی شدن که خودشون این خصیصه رو هم دارن، ولی ظاهرا در mcrypt این مدها پشتیبانی نمیشه، مگر شاید آخرین نسخه هاش.

حالا این MAC خودش یک داستان مجزا داره. مثلا یک کلید نیاز داره که خیلی ها از همون کلید رمزگذاری AES براش استفاده میکنن که توسط متخصصان به هیچ وجه توصیه نمیشه، بعضیا مثلا از کلید هش میگیرن و این هش رو استفاده میکنن (من خودم در نسل قبلی کدهام این کار رو کردم - این باز خیلی بهتره ولی هنوزم طبق علم و اصول دقیقش نیست)، ولی الان من از HKDF استفاده کردم که برای همین کارها و طبق علم و اصولش توسط متخصصان طراحی شده، یعنی زمانیکه شما میخوای یک یا چند کلید رو از یک کلید اصلی مشتق کنی بهتره از HKDF استفاده کنی.

دقت میکنی اینا که میگیم هیچکدام جزو خود AES نیست، بلکه ملحقات و نیازمندی های جانبی است!
mcrypt فقط شامل یکسری الگوریتم رمزگذاریه و چیز دیگه نداره. مثل آجر هست که نیاز به ملات و سیمان و ماسه هم داره، البته میتونی همینطور آجر خشک رو روی هم بچینی، که خیلی ها اشتباها این کار رو کردن و میکنن! ولی در اصل ملات و بند و بساط دیگری هم میخواد.

همینطور هست بحث تابع رندوم که مثلا باهاش کلیدها (اهمیت اساسی) یا چیزهایی مثل IV (اهمیت به مراتب کمتر) رو تولید میکنی. از هر تابعی نمیشه و نباید استفاده کرد. باز اینم خودش داستان داره که بخوام توضیح بدم مثنوی میشه...

من سعی کردم همهء اینا رو توی یک کد سرهم کنم و همهء کارهای جانبی لازم رو خودش انجام بده.

اکثرا افراد این همه جزییات و مخلفات و مراحل لازم رو اطلاع ندارن و بنابراین از رمزنگاری های ناقص و ضعیف تر از حدی که باید باشه استفاده میکنن، بعضی وقتا اشتباهات فاحش هست و امنیت به شدت پایین میاد. مثلا خیلی ها از پسورد استفاده میکنن، درحالیکه پسورد با کلید تفاوت زیادی داره، و برای تبدیل پسورد به کلید باید از یک PBKDF استفاده کرد (نه از هش ساده یا حتی HKDF)، البته منظور از PBKDF هم لزوما مثلا PBKDF2 نیست، بلکه الگوریتم های جدیدتر و امن تری مثل bcrypt حداقل. درحالیکه خیلی ها دارن از الگوریتم های قدیمی که برای الان ضعیف محسوب میشن استفاده میکنن.
تازه اصلا خیلی جاها نباید از پسورد استفاده کرد و باید بجاش کلید باشه، ولی خیلی ها تفاوتش رو نمیدونن متوجه نیستن. ضمنا پسورد هم اگر استفاده کردیم باز خودش حساب و کتاب داره که چند بیت حداقل randomness داشته باشه که فلان حد امنیت مورد نظر رو کسب کنیم (این وسط باید تاثیر key stretching در PBKDF رو هم بحساب آورد).

بهرحال این mcrypt که گفتی معلوم نیست منظورت دقیقا چیه، احتمالا این مواردی رو که گفتم متوجه نبودی. اگر یه نمونه کد مورد نظرت رو بذاری بهت میگم کمبودها و اشکالاتش چیه.

کلا علم رمزنگاری خیلی گسترده و پیچیده است و ظرافت زیاد داره، و اغلب هم بخاطر کم اطلاعی دست کم گرفته میشه و نرخ اشتباهات در این زمینه بسیار زیاده چون وقتی یک سیستم امنیتی ضعف داره معمولا هیچ راهی نداره که خود برنامه نویس با تست و اینها بفهمه و کس دیگری هم پیدا نمیشه که این کار رو انجام بده و مثل کد و برنامه های عادی نیست که اگر چیزی به شدت و اساسا هم اشتباه باشه برنامه با مشکل جدی مواجه بشه و مثلا خطایی چیزی بده باگی چیزی مشاهده بشه در هنگام توسعه و تست. حکایت همون آجر بدون ملات چیدن هست که با یک زلزله خفیف یا حتی باد شدید ممکنه فرو بریزه، ولی خیلی وقتا این زلزله و باد شدید در عمل تا مدتهای طولانی یا حتی هیچوقت درمورد اون برنامه و کاربرد خاص رخ نمیده.
من خودم این چیزها که الان راحت برات لیست میکنم دمار از روزگارم در اومد طی چند سال با کلی مطالعه و تحقیق و برخورد کردم به مرور فهمیدم و برام روشن شد، و در طول این مدت ابهام برام زیاد وجود داشت توی خیلی موارد گیج میزدم و سوالات زیادی داشتم. تازه هر چند وقت هم این فیلد پیشرفت میکنه و چیزای جدیدی درمیاد که باید سعی کنی خودت رو آپدیت کنی.
  پاسخ
تشکر شده توسط :
#4
چی شد؟ Huh
نظری نداشتی؟ Big Grin
  پاسخ
تشکر شده توسط :
#5
من دیدم خودت رفتی الگوریتمش رو پیاده سازی کردی. چون این کتابخونه هست http://mcrypt.sourceforge.net/ که برای php و چند تا زبون دیگه به صورت اکستنشن نوشتن. بیشتر برام سوال بود که چرا خودت الگوریتمش رو پیاده سازی کردی . مگه mcrypt خودش مشکلی داره؟ اونم الگوریتم های زیادی رو پشتیبانی می کنه

کد:
cast-128 (16): cbc cfb ctr ecb ncfb nofb ofb
gost (32): cbc cfb ctr ecb ncfb nofb ofb
rijndael-128 (32): cbc cfb ctr ecb ncfb nofb ofb
twofish (32): cbc cfb ctr ecb ncfb nofb ofb
arcfour (256): stream
cast-256 (32): cbc cfb ctr ecb ncfb nofb ofb
loki97 (32): cbc cfb ctr ecb ncfb nofb ofb
rijndael-192 (32): cbc cfb ctr ecb ncfb nofb ofb
saferplus (32): cbc cfb ctr ecb ncfb nofb ofb
wake (32): stream
blowfish-compat (56): cbc cfb ctr ecb ncfb nofb ofb
des (8): cbc cfb ctr ecb ncfb nofb ofb
rijndael-256 (32): cbc cfb ctr ecb ncfb nofb ofb
serpent (32): cbc cfb ctr ecb ncfb nofb ofb
xtea (16): cbc cfb ctr ecb ncfb nofb ofb
blowfish (56): cbc cfb ctr ecb ncfb nofb ofb
enigma (13): stream
rc2 (128): cbc cfb ctr ecb ncfb nofb ofb
tripledes (24): cbc cfb ctr ecb ncfb nofb ofb

حالا نحوه استفاده از الگوریتم ها جای خودش. که من البته به اندازه تو اطلاعات در موردشون ندارم فقط اطلاعات اندکی در مورد استفاده درست ازشون دارم و خیلی عمیق واردش نشدم. مطلبت جالب بود
  پاسخ
تشکر شده توسط : vejmad
#6
(۱۳۹۵ بهمن ۰۸, ۰۱:۴۰ ق.ظ)admin نوشته:
کد:
cast-128 (16): cbc cfb ctr ecb ncfb nofb ofb
gost (32): cbc cfb ctr ecb ncfb nofb ofb
rijndael-128 (32): cbc cfb ctr ecb ncfb nofb ofb
twofish (32): cbc cfb ctr ecb ncfb nofb ofb
arcfour (256): stream
cast-256 (32): cbc cfb ctr ecb ncfb nofb ofb
loki97 (32): cbc cfb ctr ecb ncfb nofb ofb
rijndael-192 (32): cbc cfb ctr ecb ncfb nofb ofb
saferplus (32): cbc cfb ctr ecb ncfb nofb ofb
wake (32): stream
blowfish-compat (56): cbc cfb ctr ecb ncfb nofb ofb
des (8): cbc cfb ctr ecb ncfb nofb ofb
rijndael-256 (32): cbc cfb ctr ecb ncfb nofb ofb
serpent (32): cbc cfb ctr ecb ncfb nofb ofb
xtea (16): cbc cfb ctr ecb ncfb nofb ofb
blowfish (56): cbc cfb ctr ecb ncfb nofb ofb
enigma (13): stream
rc2 (128): cbc cfb ctr ecb ncfb nofb ofb
tripledes (24): cbc cfb ctr ecb ncfb nofb ofb
الگوریتم که زیاد هست، که البته روش کار اکثرشون تا حد زیادی با هم اشتراک داره و بیشتر در یکسری جزییات جانبی تفاوت میکنن (البته این جزییات میتونه در عمل خیلی تاثیرگذار باشه)، ولی معمولا دلیلی نداره از الگوریتم های کمتر شناخته شده استفاده کنیم. AES/rijndael هنوزم استانداردترین و شناخته شده ترین و پرکاربردترین الگوریتم هست که امتحان خوشو در طول سالها پس داده.
البته الگوریتم های جدیدتر از AES هم آمده که یکسری خصوصیات برتری دارن (مثلا ایمنی در برابر side channel attack)، ولی خب بازم در اکثر موارد میشه از AES استفاده کرد و مشکل جدی نداره، و استفاده از الگوریتم های جدید دردسر و ابهام هایی میتونه داشته باشه هم از نظر فنی و هم از نظر امنیتی.
حالا به هر دلیلی شاید یکی بخواد از چیزی غیر از AES استفاده کنه، لزوما اشکالی نداره، ولی همینطور کورکورانه نباید این کار رو بکنه و اول باید یه مطالعه و تحقیقی بکنه، چون خیلی از الگوریتم هایی که وجود دارن و حتی توی کتابخانه هایی مثل mcrypt هم هست، ضعفهای امنیتی قابل توجه دارن و حتی بعضیا عملا شکسته شدن. مثلا الان در این لیست، des یک الگوریتم واقعا ضعیف هست که سالها پیش شکسته شده! حالا اینکه توی کتابخانه گذاشتن دلیل نمیشه فکر کنیم ایمن است. گذاشتنش معمولا دلایل و کاربردهای خاصی داره (مثلا بخاطر دسترسی و استفاده در سیستمها و داده های قدیمی که از این الگوریتم استفاده کردن).
بطور کلی هم متخصصان به الگوریتم های کمتر شناخته شده و کمتر تحلیل شده با دیدهء تردید نگاه میکنن. هیچ الگوریتمی به اندازهء AES در طول سالها مورد Cryptanalysis (تحلیل و بررسی علمی توسط متخصصان) واقع نشده. حتی جاهایی دیدم بعضی افراد اشاره کردن که چون AES128 خیلی بیشتر از AES256 تحلیل و بررسی کارشناسی شده، پس نمیشه زیاد هم مطمئن بود که امنیت AES256 از AES128 در عمل بیشتر باشه.
بعد راستی این مدهایی هم که نوشته، مثلا cbc، ecb و غیره، اینا هم به همین شکل جزییات و خواص و تفاوت های مهمی دارن که کسی اگر اطلاع نداشته باشه احتمال اینکه اشتباهی بکنه زیاده، مثلا مد ecb میشه گفت عملا دیگه هیچکس استفاده نمیکنه و یک مد قدیمی و ضعیفی است که در بعضی موارد میتونه منجر به ضعف امنیتی جدی بشه. یا بعضی مدها هست خواص و شکل استفادهء خاصی رو دارن که اگر رعایت نشه میتونه امنیت رو از بین ببره. بنده همیشه از CBC استفاده میکنم، چون خوب درموردش مطالعه و تحقیق کردم و طرز کارش رو درک کردم و متوجه شدم یکی از پرکاربردترین و امن ترین مدهاست. البته مدهای دیگر هم خواص دیگری دارن که در بعضی کاربردها مهمه یا اصلا نیاز هست و بخاطر همین نمیشه گفت همه جا میشه از مد CBC استفاده کرد، ولی برای من تاحالا اون موردهای خاص پیش نیامده و بنظرم در عمدهء کاربردهای عادی که بیشترش مشتمل بر رمزگذاری و ذخیره سازی کل یک دیتایی و بعد رمزگشایی است مد CBC قابل استفاده است.
  پاسخ
تشکر شده توسط :


پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان