امروز میخوام براتون از رمزنگاری دوسویه یا دو کلیده بگم، این رمزنگاری دنیای اطلاعات رو زیر و رو کرده! تو جهان امروز هر جا رو که نگاه میکنی ردپای این رمزنگاری هست! HTTPS ،SSH، ارز های دیجیتال، شبکههای مجازی و … همه و همه دارن از این روش برای حفظ امنیت استفاده میکنن.
آنچه خواهید خواند!
- در ابتدا خواهم گفت در صورت نبود رمزنگاری اطلاعات چطور لو میروند
- بعد یه دید کلی از رمزنگاری میدم و میگم چرا نمیشه از روش های رایج استفاده کرد
- سپس روش رمزنگاری دوسویه رو به زبون ساده توضیح میدهم
- در ادامه از چگونگی استفاده آن در وب میگم
- چند خط کد مینویسیم و در پایتون از این روش استفاده میکنیم
چگونه اطلاعات لو میروند؟
هر دادهای که سیستم شما (یا گوشی شما) با در یک شبکه جابهجا میکند (چه شبکه کوچک خانگی و چه در وب) از چند گره خواهد گذشت. حتی اگه اتصال شما به اینترنت را در نظر بگیریم اولین گره روتری(به فارسی: مسیریاب) هست که بهش وصلید. این اطلاعات میتوانند شامل اطلاعات حساب، پیام های پیامرسان، ایمیل و … شود. در صورت نبود رمزنگاری تمام این اطلاعات به صورت خام و خوانا در شبکه عبور میکند. این اطلاعات بخش زیادیش به صورت متن هست مثلا سایتی که در اون نام کاربری و رمز وارد میکنید همش به صورت متنی برای سرور ارسال میشن. این اتفاقیست که در پروتکل های HTTP ،Telnet و FTP رخ میدهد. در عملیاتی به نام Sniffing هکر(که به معنی فردی وارد به کامپیوتر است، نه حتماً یک خرابکار!) با استفاده از ابزارهایی این اطلاعات را میخواند. اینجا براتون یک مثال از FormData آوردم:
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
name=Maria+Smith&age=19
زمانی که در یک شبکه هستید اعضای شبکه میتونن در روش هایی مثل Sniff یا Man-in-middle اطلاعتی که از شبکه عبور میکند را ببینند.
علاوه بر این در پیامرسانها پیامی که ارسال میکنید از سرورهای پیامرسان عبور میکند(و یا ذخیره میشود) درصورت نبود رمزنگاری، تمامی پیامها خوانا هستند و حریم خصوصی کاربران در خطر خواهد بود.
رمزنگاری
اصولا به هر روشی که داده اصلی رو به شکلی قابل بازگشایی تغییر دهد رمزنگاری میگوییم. سادهترین رمزنگاریها هیچ یا یک کلید دارند (البته چیزی به نام رمزنگاری یکسویه داریم ولی از بحث فعلی خارج هستن)
احتمالا اون دسته از خواننده های قدیمی و خفن ما که سال هاست با ما هستن یه چیزایی از روش ویجنری که من سال ها پیش یاد گرفته بودم و رو وبلاگ قبلیمون مطلب نوشته بودم یادشون باشه.
زمانی که در رمزنگاری از یک کلید استفاده بشه یعنی همون کلیدی که برای رمزنگاری استفاده میشه عیناً برای بازگشایی رمز هم استفاده میشه؛ این یعنی تمام تلاش برای حفظ کلید باید انجام بشه. اگر بخواهیم برای حفظ امنیت و حریم شخصی از چنین روش هایی استفاده کنیم چه اتفاقی میافتد؟
زمانی که سیستم شما قرار است با یک سرور ارتباط بگیرد و داده های رمز شده را تبادل کند اولین قدم این است که دو طرف بدانند با چه کلیدی قرار است رمزنگاری و رمزگشایی صورت گیرد. زمانی که شبکه ناامن باشد تبادل هر کلیدی معادل لو رفتن کلید و خونده شدن کل رمز میشود. اگر هم تبادل کلید را حذف کنیم دیگر HTTPS و … غیر ممکن میشود!
رمزنگاری دو سویه عمومی و خصوصی
ایده اولیه رمزنگاری با کلید عمومی (دو کلیده یا دو سویه) توسط Martin Hellman, Ralph Merkle و Whitfield Diffie در دانشگاه Stanford و در سال ۱۹۷۶ مطرح شد. کلیت ماجرا به این شکل هست که یک کلید خصوصی (private key) هست که مجموعهای از اعداد تصادفی بزرگ هست؛ معمولا برای ساختش میگن موس بچرخونید و کارای این مدلی تا اعداد تا جایی که میشه تصادفی باشن. از کلید خصوصی با فرمولی میشه کلید های دیگهای به نام کلید عمومی (public key) ساخت. برای ساخت کلید های عمومی از یک الگوریتم یک طرفه استفاده میشه طوری که نمیشه از کلید عمومی به کلید خصوصی رسید. در واقع میشه ولی به میلیونها یا میلیاردها کلید خصوصی میرسه که نمیشه گفت کدوم یکی درسته، این مقدار گاهی از تعداد اتمهای کل جهان هستی بیشتر هم میشه!
جالبی ماجرا اینجاست که رمزنگاری توسط کلیدهای عمومی انجام میشن ولی رمزگشایی فقط توسط کلید خصوصی میتونه انجام بشه. این یعنی شما یک کلید خصوصی دارید و میتونید کلیدهای عمومیتون رو به جهان بدید تا رمزهای خودشون رو براتون بفرستن. هیچکی نمیتونه رمز کس دیگهای رو بخونه و فقط شما هستید که میتونید با کلید خصوصی تون رمز ها رو بخونید. برای این که شما هم بتونید رمزنگاری کنید باید از دیگران کلید عمومی بگیرید تا برای اون رمز بفرستید. شاید خودتون در جریان نباشید ولی در طول روز بار ها این کار رو میکنید!
رمزنگاری دو سویه کلید عصر ارتباطات
زمانی که به یک سایت با پروتکل HTTPS میرید، ساده ترین کاری که انجام میشه اینه که مرورگر شما از سرور اون سایت میخواد که کلید عمومی برای مرورگر بفرسته. تا اینجا مرورگر که کلید عمومی رو داره میتونه برای سرور رمز بفرسته ولی جواب های سرور باید با چه کلیدی رمز بشن؟ برای همین مرورگر شما هم یک کلید عمومی برای سرور میفرسته تا سرور پاسخ درخواست ها رو با اون رمز کنه. خب کلید های خصوصی چی شدن؟! جواب مشخصه، کلید خصوصی محرمانه ترین چیزی هست که سرور و مرورگر پیش خودشون نگه میدارن تا ارتباط لو نره.
البته این وسط بحث های دیگهای مثل امضا کردن و … هست که اصالت کلید و این که متعلق به کی هست رو تایید میکنه ولی فعلا از اونا صرف نظر میکنیم.
زمانی که شما در پیامرسانتون گزینه رمزنگاری رو فعال میکنید (امیدوار هستیم که) پیامرسان شما و دوستتون که دارید باهاش چت میکنید با هم کلید های عمومی رو به اشتراک بگذارن تا بتونن پیام ها رو با رمز جابهجا کنن. نکته این هست که اولاً باید از این ماجرا مطمئن شد، چون تا زمانی که سورس باز نباشه نمیشه این رو تایید کرد، و دوماً کلید خصوصی کجا ذخیره میشه؟ اگه مثل تلگرام قراره رو سیستم یک نفر دیگه (همون سرور!) ذخیره بشه که فایده نداره!
جالب ترین بخش ماجرا اینه دنیای ارز دیجیتال و بلاکچین و … همهش به لطف وجود شیوه های رمزنگاری مختلف خصوصا همین شیوه رمزنگاری با کلید عمومی به وجود اومدن، البته من (بهنام سیمجو) توی این حوضه اطلاعات جامعی ندارم ولی طبق چیزی که متوجه شدم ماجرا اینه که مثلا زمان دریافت بیتکوین (/کش) اون آدرسی که برای فرستنده (واریزکننده) میفرستید در واقع یک کلید عمومی هست و کیف پول شما حاوی کلید خصوصی هست. از این کلیدها برای امضا و ثبت یک تراکنش در لجر (دفتر ثبت تراکنشها) که در واقع همون شبکه بلاکچین هست استفاده میشه.
همونطور که گفتم درمورد آخر اطلاعات جامعی ندارم و اگر نکتهای بود خوشحال میشم تو کامنت ها بگید.
رمزنگاری دوسویه در کد
یکی از متد های رایجی که در اون از رمزنگاری دو سویه استفاده شده RSA هست. این متد در SSH بسیار رایج هست.
pip install rsa
- ابتدا کتابخوانه rsa را وارد کنید
- کلیدهای عمومی و خصوصی را بسازید(یا بگیرید)
- پیام را به باینری انکود (Encode) کنید
- پیامتان را با کلید عمومی رمزنگاری کنید
- میتوانید با کلید خصوصی رمزگشایی کنید
import rsa
public_key, private_key = rsa.newkeys(512)
message = "Hello pcworms!"
enc_message = rsa.encrypt(message.encode(), public_key)
print(f'{message=}')
print("encrypted string: ", enc_message)
dec_message = rsa.decrypt(enc_message, private_key).decode()
print("decrypted string: ", dec_message)