رمزنگاری AES-128 بین Python و PHP

این بند و بساط رو برای پروژه خودم نیاز داشتم که نوشتم.
آیندگان از بنده ممنون خواهند بود که زحمت این کار رو کشیدم، چون کار راحتی نیست و نیاز به تحقیق و تخصص داره :D
بهرحال ما هر چه دانش داریم مدیون جنبش نرم افزار آزاد و بازمتن هستیم، و اشتراک گذاری رایگان اطلاعات عظیم علمی در اینترنت، و بنابراین «باید» هروقت که میتونیم ما هم به این فرهنگ و جامعه بازپرداختی داشته باشیم و دانش و ابزارهایی رو که بدست میاریم با دیگران به اشتراک بذاریم!
این یک فریضهء الهی است :D
البته استثناء این فریضه، مواردی هست که واضحا ازشون بیشتر سوء استفاده میشه تا استفادهء مفید.

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

از این قدرت مخوف لذت ببرید. قدرت رمزنگاری ای که اگر درست انجام بشه هیچکس در دنیا قادر به شکستن اون نیست!

خب من تمام فایلها و بند و بساط رو توی این فایل زیپ گذاشتم: python-php-encryption.zip

توضیحات:
رمزنگاری مورد استفاده: AES-128-CBC+HMAC-SHA256

خیلی از رمزنگاری ها که شما در نت پیدا میکنید دارای MAC نیستن و این ویژگی رو بنده به نمونه کدهایی که پیدا کردم اضافه کردم. وظیفهء HMAC حفاظت از داده ها در برابر دستکاری یا تغییر تصادفیه. رمزنگاری AES128 (در حالت CBC) به تنهایی Confidentiality (محرمانگی) رو تامین میکنه، اما از تغییرات تصادفی یا کورکورانهء داده های رمز شده جلوگیری نمیکنه (Integrity و Authenticity رو تامین نمیکنه). بنابراین یک رمزنگاری کامل اونه که دارای MAC هم باشه.

راستی تابع str2key (در فایل crypto.py) برای تبدیل یک رشته به کلید باینری 128 بیتی مورد نیاز برای رمزنگاری AES128 استفاده میشه.
عملا ما یک رشته رو بعنوان کلید به توابع encrypt و decrypt پاس میکنیم. البته ابتدا این توابع رو طوری نوشته بودم که مستقیما کلید باینری 128 بیتی رو بهشون بدیم، ولی بعد دیدم نوشتن رشته های معمولی بعنوان کلید در کد ساده تره، بخاطر همین تابع str2key رو نوشتم. این تابع از رشته هش SHA256 میگیره و بعد خروجی اون رو (دقت کنید خروجی باینری و نه هگز) که 256 بیت است به 128 بیت Truncate میکنه (قبلا در crypto.stackexchange.com در این باره (Truncate کردن خروجی هش) سوال و تحقیق کرده بودم و مطمئن بودم که از نظر امنیتی مشکل جدی نداره).
و اما خب ما این کلیدها رو چطوری باید انتخاب کنیم. خیلی مهمه! چون امنیت رمزنگاری شما هیچوقت از کیفیت کلید شما نمیتونه فراتر بره. مثلا اگر از پسورد abc123 بعنوان کلید استفاده کنید، امنیت خیلی پایین خواهد بود، چون اینطور پسوردها خیلی ضعیف هستن.
نحوهء محاسبهء قدرت پسورد انتخاب شده (البته دقیق بخوایم بگیم اینطور رشته های طولانی و قوی رندوم رو که بعنوان کلید استفاده میشن معمولا پسورد نمی نامند و شاید همون کلید بگیم بهتر باشه) بدین صورت هست که شما باید یک رشتهء رندوم انتخاب کنید و تعداد حالتهای ممکن برای اون رو محاسبه کنید که از یک حداقلی کمتر نباشه. حداقل امنیت درست و حسابی 80 بیت است (البته برای کاربردهایی که خیلی حساس نیستن و نیاز به تامین امنیت برای مدت طولانی (سالها) ندارن)، اما توصیه میشه بیشتر از این باشه و چه بهتر که به همون 128 بیت برسه و با حداکثر امنیت AES128 مچ بشه.
بطور مثال فرض کنید من رشته ای رندوم به این صورت انتخاب میکنم: حروف بزرگ و کوچک انگلیسی+اعداد+علامتهای خاص روی کیبورد. فرض میکنیم طول این رشته 18 کاراکتر باشه.
حالا محاسبهء امنیت این کلید بر حسب بیت به این شکل است: حروف کوچک انگلیسی 26 عدد+حروف بزرگ 26 عدد+اعداد 10 عدد+علامتهای خاص 20 عدد (حدودی یک مقدار کمترش رو گرفتم)=82
حالا 82 رو به توان 18 میرسونیم تا تعداد حالتهای ممکن مشخص بشه: 2.8×10^34
خب اگر یخورده توان های 2 رو محاسبه کنید میبینید که این عدد یک چیزی بین 2 به توان 114 و 2 به توان 115 است، پس یک کلید با امنیت کافی (در کاربردهای عادی که خیلی حساس نیستن و نیاز به محرمانگی طولانی مدت ندارن) محسوب میشه. امنیتش بر حسب بیت تقریبا همون 114 بیت است.
البته اگر دیتای شما واقعا حساس است بطوریکه ممکنه هکرهای قوی با انگیزه و منابع مالی و امکانات قوی تا سالها دنبال رمزگشایی داده های شما باشن، توصیه میکنم امنیت رو به 128 بیت برسونید. ضمنا در این مورد انتخاب کلید قوی تر از 128 بیت فایده ای نداره، چون الگوریتم رمزنگاری ما امنیتش تا 128 است و نه بیشتر. اگر اطلاعاتی که میخوان رمز بشن از نوع فوق محرمانه هستند، مثلا اسناد حکومتی و مربوط به امنیت ملی کشور هستن که باید برای بیش از 10 سال بشه از امنیت رمزنگاری اونها مطمئن بود، اونوقت توصیه میشه از AES256 استفاده بشه. ولی بنده موارد استفاده AES256 رو خیلی کم و انحصاری میبینم و در 99.99% کارهای برنامه نویسان عادی فکر نمیکنم چنین نیازی هیچوقت پیش بیاد، و از اون طرف AES256 از AES128 به میزان قابل توجهی پردازش بیشتری طلب میکنه و کندتره و حجم خروجی اون هم خیلی وقتا بیشتر میشه، بخاطر همین از پیاده سازی و استفاده این الگوریتم صرفنظر کردم. همین AES128 هم در حال حاضر امنیت بسیار زیادی داره و تا سالها امید نمیره حتی قوی ترین کشورها بتونن اون رو بشکنن (مگر اینکه در ظرف چند سال آینده رایانه های کوانتمی قوی ساخته بشن که چنین چیزی با توجه به تحقیقاتی که در این زمینه داشتم و اطلاعاتی که دارم بعید بنظر میاد). باید اینو بدونید وقتی در خیلی از کاربردها از AES256 صحبت میکنن، بیشتر جنبهء تبلیغات و غلو داره تا اینکه در عمل مزیت بحساب آمدنی باشه. این بخاطر مسائل و پارامترهای متعددی هست که در رمزنگاری دخیل هستند. ضمنا خیلی وقتا سیستمهایی که ادعا میکنن از رمزنگاری های خیلی قوی استفاده میکنن، در بخشهای دیگری دچار ضعف هستند که باعث میشه اون رمزنگاری قوی عملا اهمیت و فایده ای نداشته باشه! تقریبا همیشه امنیت سیستمها در بخشهای دیگری خدشه دار و شکسته میشه و خیلی کم به این ربط داره که ما بین رمزنگاری 128 بیت و 256 بیت کدام رو انتخاب کرده ایم. یکی از مسائل حساس دیگر اینه که شما یک کلید قوی با امنیت مناسب تولید کنید، که این کار معمولا توسط توابع CSPRNG انجام میشه.

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

اوه راستی یادم رفتم بگم! شما ابتدا باید ماجول pycrypto رو برای پایتون خودتون نصب کنید، چون پایتون بصورت پیشفرض این ماجول رو نداره. بنده اول سرچ کردم و مطالبی خوندم مثلا نوشته بودن چطور این ماجول رو تحت لینوکس یا ویندوز کامپایل کنیم، و بنظرم رسید کار طولانی و سختی باشه، ولی دست آخر نسخهء کامپایل شده و آمادهء این ماجول برای ویندوز رو پیدا و دانلود کردم که براحتی نصب شد. ضمنا دقت کنید ظاهرا هر نسخه از پایتون نسخهء کامپایل مخصوص خودش رو میخواد.

ضمنا درسته قبلا رمزنگاری در PHP رو گذاشته بودم، ولی اون با نسخهء پایتون سازگاری نداشت (چند تفاوت کوچک داشت مثلا اینکه از HMAC-SHA1 استفاده میکرد)، بخاطر همین توابع اون کتابخانه رو مقداری تغییر دادم تا با نسخهء پایتون سازگار بشه.

ضمنا قسمت مقایسهء صحت HMAC در این توابع طوری طراحی شده که در برابر حمله های آنالیز زمانی هم مقاومت داشته باشه. فکر نمیکنم چیزی ساده تر و جمع و جورتر و در عین حال کاملتر از این توابع جایی پیدا کنید! چون خودم نت رو گشتم و تحقیق کردم و از بین کدها و روشهای مختلف بالاخره اینها رو سرهم کردم.

راستی یادتون باشه رمزنگاری به تنهایی جلوی تمام حمله ها رو نمیگیره. بخصوص مثلا باید به حملهء Replay اشاره کنم که در برنامه های شبکه ای/اینترنتی مطرح هست و روش جلوگیری ازش خارج از حیطهء توانایی این توابعی هست که اینجا گذاشتم. بنده با شامل کردن شمارنده و تشکیلات دیگری در برنامهء خودم جلوی این حمله رو گرفتم.

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>