PDA

View Full Version : آموزش استفادهء ساده از رمزنگاری متقارن (AES128-CBC)



eshpilen
چهارشنبه 02 آذر 1390, 15:35 عصر
اخیرا برای پروژهء خودم دنبال کتابخانهء رمزنگاری مناسبی بودم. البته در PHP اکستنشن mcrypt وجود داره، ولی ممکنه روی بعضی سرورها و یا نسخه های قدیمی تر نصب یا فعال نباشه. بنابراین دنبال پیاده سازیهایی خالص در PHP بودم که نیاز به اکستنشن نداشته باشن.

از بین چند مورد یکی رو پیدا کردم که بنظرم از همه بهتره: http://phpseclib.sourceforge.net

مزایاش نسبت به بقیهء موارد:
- بجای فقط یک الگوریتم رمزنگاری یه پروژهء و کتابخانهء نسبتا گسترده هست که شامل الگوریتم ها و پروتکل های مختلفی میشه (مثلا حتی پروتکل SSH رو داره).
- بر اساس بنچمارک و ادعای خودش (http://phpseclib.sourceforge.net/documentation/sym_crypt.html#sym_crypt_aes_benchmarks_table) سریعترین پیاده سازی رو در بین بقیهء پیاده سازیهای PHP داره.
- اگر mcrypt در دسترس باشه از mcrypt استفاده میکنه (که سرعتش بهرحال بالاتره)، وگرنه از پیاده سازی داخلی خودش استفاده میکنه. و همینطور برای بقیهء الگوریتم ها؛ بطور مثال اگر تابع hash در دسترس باشه از اون برای الگوریتم هش استفاده میکنه، وگرنه از پیاده سازی داخلی خودش.

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

اما من برای پروژهء خودم چنتا الگوریتم و کلاسها و تابعی رو که برای رمزنگاری بازگشت‌پذیر متقارن لازم داشتم در یک فایل ادغام کردم. فکر میکنم به این شکل برای شما و آموزش این تاپیک هم خیلی بهتره و ساده تر میشه؛ بنابراین یک فایل رو که الان از ادغام چند فایل دیگر این پروژهء درست کردم ضمیمهء این پست میکنم و مثالها با استفاده از اون فایل انجام میشه. اسم فایل رو گذاشتم crypto.php.
البته ناگفته نماند یه چنتا تغییر برای این کار و دو سه تا تابع کوچک هم از خودم اضافه کردم.
بطور مثال متدهای IvEncrypt و IvDecrypt رو خودم به کلاس Crypt_AES اضافه کردم.
البته بابت امنیت تغییراتی که بنده ایجاد کردم و توابع اضافه شده چندان نگران نباشید چون هستهء کار با الگوریتم های اصلی خود کتابخانه انجام میشه و توابع بنده بیشتر جنبهء خلاصه سازی و ساده سازی مراحل رو دارن. مثلا بجای اینکه چند مرحله و چند خط کد بنویسیم که احتمالا بیشتر افراد سردرنمیارن چی هست و چطوری چکار میکنه، کافیه از یک خط و یک تابع استفاده کنیم.

خب یه مثال از رمزنگاری متقارن با استفاده از الگوریتم AES با طول کلید 128 بیت و در مد CBC:


<?php

require_once 'crypto.php';

$plaintext='a secret string!';

$aes = new Crypt_AES();//default: 128 bits - CBC mode

$key=random_bytes(16);

$aes->setKey($key);

$ciphertext=$aes->IvEncrypt($plaintext);

echo 'Plaintext: ', $plaintext, '<br />';
echo 'key: ', bin2hex($key), '<br />';
echo 'chiphertext: ', bin2hex($ciphertext), '<br />';

$plaintext2=$aes->IvDecrypt($ciphertext);

echo 'Plaintext2: ', $plaintext2, '<br />';

?>

خروجی برنامه چیزی مشابه این خواهد بود:

Plaintext: a secret string!
key: 94fe096d309b482af01812a037561d21
chiphertext: 833d1a1a7dd843f93561baeb448c69885501856804fb8deac2 4177ba18bdf0ff6c6ec6d1a1690c86bc8b78ed2c46fa30
Plaintext2: a secret string!
Plaintext متن اصلی ما بوده که میخواستیم رمز کنیم.
key کلید رمزنگاری هست که بصورت رندوم توسط تابع random_bytes ایجاد شده و حاوی 16 بایت (معادل 128 بیت) با مقدار تصادفی هست.
وقتی ما کلید یک الگوریتم رمزنگاری رو بصورت مستقیم تعیین میکنیم، مثلا اگر 128 بیت باشه، باید 128 بیت یا 16 بایت بهش بدیم. تعیین مستقیم کلید با پسورد فرق داره. بعد نمونه کد برای استفاده از متد مربوط به تعیین پسورد رو خواهیم دید. وقتی بجای کلید پسورد میدیم، پسورد توسط الگوریتم مخصوصی بصورت داخلی تبدیل به یک کلید (با طول 128 بیت، 256 بیت و غیره) میشه و این کلید هست که برای رمزنگاری استفاده میشه.
در خیلی کاربردها از پسورد استفاده میشه، اما در خیلی جاها هم نیازی به تعیین دستی پسورد نیست و برنامه خودش بصورت خودکار یک کلید تصادفی تولید میکنه (مثل کد مثال ما). امنیت کلید معمولا خیلی بیشتر از پسورد هست، چون پسورد توسط انسان انتخاب میشه و معمولا طول و آنتروپی کمی داره و میتونه بیش از حد ضعیف باشه، اما مثلا یک کلید 128 بیتی که رندوم تولید میشه معادل یک پسورد 16 کاراکتری کاملا رندوم هست که امنیت خیلی بالایی داره.
chiphertext خروجی رمز ما هست که میتونیم با خیال راحت از اینکه کسی نمیتونه اون رو رمزگشایی کنه منتقل یا ذخیرش کنیم. البته chiphertext خروجی از الگوریتم ما در فرمت باینری هست، ولی چون ما میخواستیم اون رو در مرورگر توسط دستور echo نشان بدیم، با استفاده از تابع bin2hex اون رو تبدیل به نمایش متنی در مبنای 16 کردیم. بخاطر همین تعداد بایتهای متن نمایش داده شده دوبرابر chiphertext اصلی شده، چون در نمایش هگز، مقدار هر بایت با دو کاراکتر (هر کاراکتر از 0 تا F) نمایش داده میشه.

از تبدیل به هگز میشه برای درج متن رمزی در جاهایی مثل صفحهء HTML (مثلا در یک hidden input)، ذخیره در کوکی، یا درج در پارامترهای URL استفاده کرد. به این شکل خروجی برنامه هم خوانا خواهد بود و هم از ایجاد مشکل با فرمت و کاراکترهای مجاز (مثلا در URL نمیتونیم هر بایت/کاراکتری رو همینطوری درج کنیم) جلوگیری میشه.

نکته: بجای تبدیل به هگز از تبدیل به Base64 هم میشه استفاده کرد که حجمش کمتر هم هست، ولی هگز از نظر خوانایی بهتره و موقع تست و دیباگ هم کمک میکنه.

میتونید مقدار ciphertext رو در جاهای دیگری مثل فایل یا داخل سشن همونطور تبدیل نشده و به فرمت باینری هم ذخیره کنید. چون فایل یا سشن (یا یک ستون با نوع دادهء مناسب در دیتابیس) قابلیت ذخیرهء رشته های باینری رو هم دارن.
در خط آخر برنامه ciphertext رو با استفاده از متد IvDecrypt دوباره به متن اولیه برگردوندیم و نمایش دادیم تا از صحت عمل رمزکردن و رمزگشایی اطمینان حاصل کنیم.

دقت کنید چون ما تمام این کارها رو در یک درخواست انجام دادیم و قبلا یک نمونه از کلاس Crypt_AES رو داشتیم و کلید هم قبلا ست شده بود، برای Decrypt کردن نیاز به انجام عمل دیگری نداشتیم؛ در غیر اینصورت باید مراحل ایجاد کلاس و بعد هم ست کردن کلید صحیح رو (که حتما کلید رمزنگاری رو قبلا در جایی ذخیره کردیم) انجام میدادیم.

چون ما موقع ایجاد نمونه از کلاس Crypt_AES پارامتری رو تعیین نکردیم و بعدش هم تنظیمی انجام ندادیم، بصورت پیشفرض از کلید و طول بلاک 128 بیتی و مد CBC استفاده میشه. مد CBC باید با یک IV رندوم استفاده بشه که متدهایی که بنده اضافه کردم این کار رو بصورت خودکار برای شما انجام میدن.
نقش IV این هست که اگر دیتای یکسانی رو چند بار با کلید یکسانی رمز کنید، متن رمز شده در هر بار کاملا متفاوت خواهد بود و نفوذگر نمیتونه از روی متن رمزی به یکسان بودن دیتا و کلید پی ببره.
ضمنا طول رمز خروجی این الگوریتم همیشه ضریبی از طول بلاک اون هست. یعنی مثلا 256 بیت (32 بایت) برابر دو بلاک 128 بیتی، 384 بیت (48 بایت) برابر سه بلاک، و غیره. هر بلاک 128 بیت یا 16 بایت میشه. چون ما یک بلاک IV رو هم به ابتدای رمز اضافه میکنیم، حدقل طول خروجی، دو بلاک معادل 32 بایت خواهد بود، حتی اگر رشته ای به طول یک کاراکتر رو رمز کنیم. طول پسورد تاثیری روی طول خروجی نداره و پسورد همیشه به یک کلید 128 بیتی تبدیل میشه (البته در AES128 که ما استفاده کردیم).
اینکه از روی طول خروجی نمیشه طول دقیق متن اولیه رو فهمید خودش در خیلی جاها یک مزیت امنیتی محسوب میشه یا حتی یک ویژگی لازمه.

ما در اینجا از AES128 استفاده کردیم. اما میتونستیم از طول کلید و طول بلاک 256 بیت هم استفاده کنیم، اما 128 هم برای کاربردهای معمولی کاملا امن محسوب میشه (حداقل تا 20 سال آینده کسی به کرک شدنش فکر نمیکنه؛ ضمنا اگر از پسورد استفاده کنید بهرحال معمولا کلید شما حتی از 128 بیت هم ضعیفتره).

راستی چون صحبت از تبدیل خروجی باینری به هگز کردم باید روش تبدیل معکوس یعنی از هگز به باینری رو هم نشون بدم، چون باید اول این کار رو انجام بدید تا بتونید رشته رو مجددا رمزگشایی کنید:


<?php

require_once 'crypto.php';

$plaintext='a secret string!';

$aes = new Crypt_AES();

$key=random_bytes(16);

$aes->setKey($key);

$hex_ciphertext=bin2hex($aes->IvEncrypt($plaintext));

$ciphertext=pack('H*', $hex_ciphertext);

$plaintext2=$aes->IvDecrypt($ciphertext);

echo 'Plaintext2: ', $plaintext2, '<br />';

?>


همونطور که میبینید این کار با استفاده از تابع pack براحتی انجام میشه.

یه نمونه هم از استفاده از یک پسورد ثابت بجای یک کلید رندوم:

<?php

require_once 'crypto.php';

$plaintext='a secret string!';

$aes = new Crypt_AES();

$aes->setPassword('MyPassword');

echo 'Plaintext: ', $plaintext, '<br>';

echo 'key derived from password: ', bin2hex($aes->key), '<br>';

$ciphertext=$aes->IvEncrypt($plaintext);

echo 'chiphertext: ', bin2hex($ciphertext), '<br>';

$plaintext2=$aes->IvDecrypt($ciphertext);

echo 'Plaintext2: ', $plaintext2, '<br>';

?>
نمونه خروجی:

Plaintext: a secret string!
key drived from password: b92f1896edb7e14e2bd1a4b0471fb0aec057a460
chiphertext: d8151f1b9e415f4cc2993aacb193d96368db40be4c319ba9b1 469517c69ed9bf9473ee344d84b34e81ed37a1f85462cb
Plaintext2: a secret string!
ما در این مثال کلید تولید شده بر اساس پسورد رو هم نشون دادیم.
چون پسورد ثابت هست، وقتی صفحه رو رفرش کنید کلید عوض نمیشه (چون کلید از پسورد مشتق میشه)، ولی مشاهده میکنید که متن رمزی در هربار کاملا تغییر میکنه؛ این نتیجهء استفاده از یک IV رندوم هست که البته این بخش از کار در داخل تابع IvEncrypt انجام میشه.
توجه کنید که IV بصورت رمزنشده در ابتدای متن رمز شده اضافه میشه. IV چیزی نیست که نیازی باشه بصورت محرمانه نگه داشته بشه، و برای رمزگشایی هم بهش نیاز دارید، بنابراین اون رو به ابتدای متن رمزی اضافه میکنیم تا همه جا همراهش باشه (معمولا این کار رو میکنن، اما میشه اون رو بصورت جداگانه هم ذخیره کرد).
امنیت متن رمزی شما بر محرمانه باقی موندن پسورد و کلید استواره.

راستی اگر دقت زیادی داشته باشید ممکنه متوجه بشید که اگر طول کلید تولید شده از پسورد رو که در این مثال نمایش داده شده محاسبه کنیم، بجای 128 بیت برابر 160 بیت میشه. بنده متوجه این موضوع شدم و این مسئله رو در فروم ساپورت این کتابخانه مطرح کردم (http://www.frostjedi.com/phpbb/viewtopic.php?f=46&t=26341) تا مطمئن بشم باگ و خطری درکار نیست، و به محض اینکه جوابش داده شد در تاپیک مطرح میکنم. اما احتمالا مشکلی نداره و بیشتر به جزییات پیاده سازی الگوریتم داخلی برنامه برمیگرده.

------------------------------------------

راستی ممکنه کدهای نمایش داده شده برای شما هم خراب شده باشن (کار نرم افزار فرومه!). مثلا جاهایی در کد که یک رشتهء خالی ('') میبینید، درواقع داخلش تگ <br> بوده. پس خودتون کدها رو اصلاح کنید.

eshpilen
شنبه 05 آذر 1390, 17:07 عصر
راستی اگر دقت زیادی داشته باشید ممکنه متوجه بشید که اگر طول کلید تولید شده از پسورد رو که در این مثال نمایش داده شده محاسبه کنیم، بجای 128 بیت برابر 160 بیت میشه. بنده متوجه این موضوع شدم و این مسئله رو در فروم ساپورت این کتابخانه مطرح کردم (http://www.frostjedi.com/phpbb/viewtopic.php?f=46&t=26341) تا مطمئن بشم باگ و خطری درکار نیست، و به محض اینکه جوابش داده شد در تاپیک مطرح میکنم. اما احتمالا مشکلی نداره و بیشتر به جزییات پیاده سازی الگوریتم داخلی برنامه برمیگرده.این مشکل رو در نسخهء جدید کلاسها برطرف کردن.
بنده کد آخرین نسخهء کلاسها رو گرفتم و فایل zip که ضمیمه هست رو آپدیت کردم.
کسانی که فایل زیپ قبلی رو دانلود کرده بودن لطفا نسخهء جدید رو بگیرن و فایل crypto.php خودشون رو با نسخهء جدید جایگزین کنن.

ravand
شنبه 05 آذر 1390, 20:20 عصر
سلام
متشكر از مطالبتون.
ميخواستم دقيقا بدونم اين نمونه رمزگذاري بيشتر در چه جاهايي استفاده مشه من در عمل در چه جاهايي ميتونم از اين نمونه رمزگذاري استفاده كنم؟ و اين نمونه رمز گذاري چه فرقي با تكنيك ssl داره؟

vcldeveloper
شنبه 05 آذر 1390, 21:46 عصر
ميخواستم دقيقا بدونم اين نمونه رمزگذاري بيشتر در چه جاهايي استفاده مشه من در عمل در چه جاهايي ميتونم از اين نمونه رمزگذاري استفاده كنم؟
تقریبا همه جا، به شرطی که کلید رمزنگاری به شکل امن منتقل شده باشه. تکنیک های رمزنگاری نامتقارن نیاز به توان پردازشی بالا دارند و سرعت شان نسبت به روش های متقارن بسیار کند هست؛ به همین جهت، از اون روش ها معمولا برای نقل و انتقال امن کلید رمزنگاری متقارن استفاده میشه، و بعد از اطمینان از صحت انتقال کلید رمزنگاری، از یک روش رمزنگاری متقارن برای رمز کردن ارتباط استفاده میشه.


اين نمونه رمز گذاري چه فرقي با تكنيك ssl داره؟
SSL یک الگوریتم رمزنگاری نیست، بلکه یک پروتکل امنیتی هست. در SSL برای نقل و انتقال کلید رمزنگاری از یک الگوریتم رمزنگاری نامتقارن استفاده میشه، و سپس داده های مورد نقل و انتقال با این کلید رمزنگاری و یک الگوریتم متقارن رمز میشند. الگوریتم رمزنگاری متقارن مورد استفاده یک الگوریتم ثابت نیست و ممکنه برای این بخش از الگوریتم های متقارن مختلفی مثل همین AES استفاده بشه.

eshpilen
یک شنبه 06 آذر 1390, 09:03 صبح
سلام
متشكر از مطالبتون.
ميخواستم دقيقا بدونم اين نمونه رمزگذاري بيشتر در چه جاهايي استفاده مشه من در عمل در چه جاهايي ميتونم از اين نمونه رمزگذاري استفاده كنم؟ و اين نمونه رمز گذاري چه فرقي با تكنيك ssl داره؟
رمزنگاری که کلا کاربرد اساسی گسترده ای در همه جا داره، اما در وب و در سمت سرور معمولا در سناریوهای خاص‌تر/پیشرفته‌تری بهش نیاز میشه.
یه مثالی که خودم ازش استفاده کردم، ایجاد امنیت برای اطلاعات محرمانه کاربران که میخواستم موقتا در سشن ذخیره کنم هست. چون میدونید که مالکان دیگر سایتها در هاستهای اشتراکی میتونن محتویات سشن های سایت شما رو بخونن. البته برای این مشکل راه حلهایی مثل تغییر دایرکتوری ذخیره سشن ها و ذخیره در دیتابیس وجود داره، اما بهتره برنامه در حالتی که این تنظیمات انجام نشدن و بهرصورت به هرعلتی سیستم سشن در حالت پیشفرض هست در این زمینه امن باشه.

ravand
یک شنبه 06 آذر 1390, 17:33 عصر
سلام خيلي مشتاقم تا در مورد اين روش رمزگذاري بيشتر بدونم.
توي گوگل سرچ كردم چيزي گيرم نيومد.
شما ميتوني يك صفحه از سايت رو روش با همين روش پسورد بذاري؟
اگه ميشه در عمل يه نمونه اسكريپتش رو براي ما اينجا بذاريد.
متشكرم.

eshpilen
یک شنبه 06 آذر 1390, 19:24 عصر
سلام خيلي مشتاقم تا در مورد اين روش رمزگذاري بيشتر بدونم.
کدوم روش؟
دقیقا منظورت از این روش چیه؟
چون رمزنگاری که یه بحث عمومی هست و کاربردهای خاص خودش رو داره.
یعنی میگم انگار یه چیز خاصی ازش برداشت کردی که نمیدونم چیه.


شما ميتوني يك صفحه از سايت رو روش با همين روش پسورد بذاري؟
یه صفحه؟
یعنی چی دقیقا؟
من فقط بعضی اطلاعات خاص رو رمز کردم، نه کل یک صفحه رو.

ravand
یک شنبه 06 آذر 1390, 19:29 عصر
کدوم روش؟
دقیقا منظورت از این روش چیه؟
چون رمزنگاری که یه بحث عمومی هست و کاربردهای خاص خودش رو داره.
یعنی میگم انگار یه چیز خاصی ازش برداشت کردی که نمیدونم چیه.


یه صفحه؟
یعنی چی دقیقا؟
من فقط بعضی اطلاعات خاص رو رمز کردم، نه کل یک صفحه رو.



ببين مثلا الان من يه يوذر توي همين سايت دارم كه بايد حتما براي وارد شدن بهش يوذر و پسوردم رو وارد كنم. ميخوام ببينم ميتونم براي يه يوذري كه خودم ميسازم براي سايتم با اين روش رمز بذارم؟

eshpilen
یک شنبه 06 آذر 1390, 21:06 عصر
بازم متوجه نشدم منظورت چیه. میشه بیشتر توضیح بدی؟
خب یوزر که خودش پسورد داره و کس دیگه نمیتونه بجای شما وارد بشه، رمزی که میگی دیگه چیه و برای چی میخوای استفاده کنی؟

ravand
دوشنبه 07 آذر 1390, 08:04 صبح
سوال من كاملاً واضح هست. براي چي متوجه نميشيد؟
ببين مثلاً من يه سيستم مديريت محتوا ساختم بعد ميخوام يه يوذر بهش بدم با يه پسورد تا كسي نتونه به غير از خودم بهش دسترسي پيدا كنه و مثلاً مطلبي رو ارسال كنه يا چيزي رو پاك كنه. من ميخوام همين پسورد رو با استفاده از رمزگذاري كه شما اينجا توضيح دادي انجام بدم و روي سيستم مديريت محتوا يه پسورد بذارم تا هر كس بخواد از سيستم مديريت محتواي من استفاده كنه پسورد بده وارد بشه . مثل بقيه ي فرم هاي log in
آيا ميشه با استفاده از اين روش روي فرم هاي لوگين مثلاً به جاي استفاده از روش SESSION از همين روش رمز گذاري نامتقارني كه شما گفتي استفاده كرد؟ اگه ميشه به عنوان مثال يه نمونه اسكريپت بذاريد.
متشكرم.

eshpilen
دوشنبه 07 آذر 1390, 11:34 صبح
برای یه احراز هویت معمولی که نیازی به رمزنگاری نیست. چون فقط کافیه پسورد تطبیق داده بشه.
سشن یه ابزار ذخیره سازی موقت اطلاعات هست، درحالیکه رمزنگاری یک ابزار برای ایمن کردن داده ها در محیطی که دیگران میتونن به اون داده ها دسترسی داشته باشن. طبیعتا میشه این دوتا رو ترکیب کرد؛ یعنی از سشن برای ذخیره اطلاعات استفاده میکنید، اما اطلاعات رو قبل از ذخیره در سشن رمز میکنید. ولی همهء اینا ربط چندانی به احراز هویت نداره.
ضمنا برای احراز هویت لزوما نیازی به سشن نیست. میشه یه کوکی معمولی محتوی یک کلید خاص باشه که با دیتابیس تطبیق داده میشه. البته این کار طبیعتا در هر درخواست انجام میشه. مزیت سشن به دیتابیس بنظرم اینه که سبک تر و سریعتر هست چون از فایلهای ساده استفاده میکنه.

eshpilen
چهارشنبه 21 دی 1390, 21:26 عصر
خب یک ضعفی که در رمزنگاری تنها وجود داره اینه که اگر کسی متن رمزی رو دستکاری کنه، این دستکاری شدن آشکار نمیشه. در بعضی کاربردها این مسئله مهم نیست اما در بعضی کاربردها هم مهمه.
بنابراین بنده توابع جدیدی رو به کلاس رمزنگاری اضافه کردم که از HMAC هم استفاده میکنن. استفاده از HMAC باعث میشه کوچکترین تغییری در دیتای رمزشده آشکارسازی بشه.
اول یک مثال از دستکاری ای رو نشون میدم که توسط توابع قبلی آشکار نمیشه:

<?php

require_once 'crypto.php';

$plaintext="a secret string!";

$aes = new Crypt_AES();

$key=random_bytes(16);

$aes->setKey($key);

$ciphertext=$aes->IvEncrypt($plaintext);

echo 'Plaintext: ', $plaintext, '<br />';
echo 'key: ', bin2hex($key), '<br />';
echo 'chiphertext: ', bin2hex($ciphertext), '<br />';

$ciphertext[14]=97;
$ciphertext[6]=100;

$plaintext2=$aes->IvDecrypt($ciphertext);

echo 'Plaintext2: ', var_dump($plaintext2);

?>
همونطور که میبینید ما دو بایت از دیتای رمز شده رو دستکاری کردیم، و این باعث میشه موقع رمزگشایی رشتهء اولیه بصورت دقیق و دست نخورده حاصل نشه. برنامهء ما متوجه این دستکاری نمیشه.

حالا این کد فرقش اینه که از توابع دارای HMAC استفاده میکنه:

<?php

require_once 'crypto.php';

$plaintext="a secret string!";

$aes = new Crypt_AES();

$key=random_bytes(16);

$aes->setKey($key);

$ciphertext=$aes->IvEncryptHmac($plaintext);

echo 'Plaintext: ', $plaintext, '<br />';
echo 'key: ', bin2hex($key), '<br />';
echo 'chiphertext: ', bin2hex($ciphertext), '<br />';

$ciphertext[14]=97;
$ciphertext[6]=100;

$plaintext2=$aes->IvDecryptHmac($ciphertext);

echo 'Plaintext2: ', var_dump($plaintext2);

?>
همونطور که در نتیجهء اجرای این کد مشاهده میکنید، درصورتیکه دیتای رمز تغییر کرده باشه، متد IvDecryptHmac مقدار false رو برمیگردونه و به این شکل میتونیم بفهمیم که دیتای رمزی صحیح نیست.

بعنوان توضیحات تکمیلی باید بگم که هزینهء استفاده از HMAC اینه که طول خروجی رمز ما به میزان 20 بایت یا 160 بیت اضافه میشه. ضمنا HMAC استفاده شده از تابع هش SHA1 استفاده میکنه (از انواع دیگر الگوریتمهای هش هم میشه استفاده کرد)، و بخاطر همین خروجی 160 بیت هست چون طول خروجی تابع SHA1 برابر 160 بیت است.

فایل جدید که علاوه بر توابع قبلی دارای توابع جدید IvEncryptHmac و IvDecryptHmac هم است ضمیمهء این پست شد.