Шифрування відкритим і закритим ключем

25

Від автора: не так давно на нашому сайті було опубліковано урок про шифрування даних на мові PHP, використовуючи розширення mcrypt. І в коментарі до нього пролунало запитання про те, як реалізувати шифрування, використовуючи відкритий і закритий ключ. Тому в даному уроці ми з Вами поговоримо про даному виді шифрування.

Шифрування відкритим і закритим ключемШифрування відкритим і закритим ключем

Введення

Хотів би одразу зазначити, що шифрування – це досить складна наука і звичайно за один урок ми з Вами не зможемо розглянути все досконально. Але, ми розглянемо – основу, тобто, як реалізувати механізм шифрування, використовуючи відкритий і закритий ключ.

Отже, системи шифрування з відкритим і закритим ключем були придумані ще в 70-х рр .. тобто – це були системи, які забезпечують передачу зашифрованих повідомлень, для розшифровки яких необхідно було використовувати ключ, відмінний від ключа шифрування. Це була головна відмінність нових систем від старих, в яких використовувався лише один ключ для шифрування і розшифровки повідомлення.
У системах шифрування з відкритим ключем використовується скрипт, що шифрує дані за допомогою відкритого ключа. Відкритий ключ — це шифр, який безпосередньо виступає інструкцією щодо шифрування повідомлення. Відкритий ключ створюється скриптом шифрування, і для кожного користувача він свій — унікальний.

Після того, як повідомлення закодовано, його можна розшифрувати лише за допомогою закритого ключа.

Шифрування відкритим і закритим ключем

Зверніть увагу на малюнок вище) – це схема роботи системи шифрування з відкритим і закритим ключем.

Отже, приміром Вам необхідно надіслати зашифроване повідомлення користувачу. Для початку необхідно отримати відкритий ключ від цього користувача. Отримавши ключ, Ви використовуючи скрипт шифрування – шифруете повідомлення і відправляєте його користувачеві. Для дешифрування повідомлень користувач використовує свій закритий ключ. При цьому для розшифровки повідомлення вже не можна скористатися відкритим ключем. Це означає, що тільки одержувач зможе прочитати повідомлення, використовуючи свій закритий ключ.

Таким чином, закритий ключ в поєднанні зі скриптом шифрування використовується для дешифрування повідомлення, зашифрованого за допомогою відкритого ключа користувача. Без знання закритого ключа дешифрувати зашифрований файл неможливо.

Що потрібно для роботи

У сьогоднішньому уроці для реалізації механізму шифрування ми будемо використовувати розширення мови PHP – OpenSSL.

Взагалі OpenSSL — це система захисту і сертифікації даних. SSL перекладається, як система безпечних сокетів (secure socket layer). OpenSSL використовується практично всіма мережевими серверами для захисту переданої інформації і це досить складна і розгалужена система. У сьогоднішньому уроці ми розглянемо лише ті моменти, які торкаються шифрування даних.

Отже, насамперед необхідно підключити розширення OpenSSL у Вашому інтерпретатор мови PHP. Для цього необхідно відкрити головний конфігураційний файл php.ini і розкоментувати рядок (прибрати символ ; спочатку даної рядки):

extension=php_openssl.dll

Після цього не забудьте перезавантажити веб-сервер. Якщо ж Ви використовуєте пакет denwer, в його базовому варіанті, то, швидше за все даного розширення у Вас немає. Вам необхідно завантажити і встановити пакет розширень для Вашої версії denwer (даний пакет можна завантажити з офіційного сайту).

Шифрування відкритим і закритим ключем

Тепер ще один момент: після установки пакету додаткових розширень і власне після раскомментирования рядка, що вказана вище – розширення openssl може так і не запрацювати. Для виправлення даної проблеми необхідно відкрити папку на вашому локальному диску) usr\local\php5 і знайти два файла: libeay32.dll і ssleay32.dll. Дані файли необхідно скопіювати і вставити в папку usr\local\apache\bin. В даній папці вже є копії цих бібліотек, але їх версії відрізняються, від бібліотек, які перебувають у інтерпретатор мови PHP (в папці usr\local\php5). Після цього перезапускаємо denwer і все має працювати. Взагалі на реальному сервері – хостингу, це розширення встановлено і коректно налаштувати.

Генерація ключів

Отже, насамперед, необхідно згенерувати ключі. Для цього ми створимо файл Enc.class.php і створимо клас, який буде логічним ядром нашого скрипта:

«private_key_bits»=>512
);
$res = openssl_pkey_new($config);
$privKey = «;
openssl_pkey_export($res,$privKey);
$fpr = fopen(«private.txt»,»w»);
fwrite($fpr,$privKey);
fclose($fpr);
$arr = array(
«countryName» => «UA»,
«stateOrProvinceName» => «Kievskaya Oblast»,
«localityName» => «Kiev»,
«organizationName» => «Organization»,
«organizationalUnitName» => «Soft»,
«commonName» => «localhost»,
«emailAddress» => «[email protected]»
);
$csr = openssl_csr_new($arr,$privKey);
$cert = openssl_csr_sign($csr,NULL, $privKey,10);
openssl_x509_export($cert,$str_cert);
$public_key = openssl_pkey_get_public($str_cert);
$public_key_details = openssl_pkey_get_details($public_key);
$public_key_string = $public_key_details[‘key’];
$fpr1 = fopen(«public.txt»,»w»);
fwrite($fpr1,$public_key_string);
fclose($fpr1);
return array(‘private’=>$privKey,’public’=>$public_key_string);
}
}
?>

В даному класі створюємо статичний метод get_keys(), який ми будемо використовувати для генерації ключів і збереження їх в текстових файлах (мається на увазі, що даний метод буде викликаний лише один раз – для генерації та запису ключів в текстові файли). Першим справу створюємо масив, конфігів, тобто задаємо параметри при створенні закритого ключа:

$config = array(
«private_key_type»=>OPENSSL_KEYTYPE_RSA,
«private_key_bits»=>512
);

Вказуємо тип ключа OPENSSL_KEYTYPE_RSA (закритий ключ для шифрування відкритим і закритим ключем) і розмір у бітах майбутнього ключа 512 біт). Далі генеруємо закритий ключ і повертаємо його дескриптор:

$res = openssl_pkey_new($config);

Витягнемо значення ключа з його дескритпора:

$privKey = «;
openssl_pkey_export($res,$privKey);

Функція openssl_pkey_export() – повертає закритий ключ у вигляді рядка і дана рядок зберігається у змінній $privKey, яка передається другим аргументом цієї функції. Перший параметр – це дескриптор ключа. Тепер давайте створимо файл index.php і виведемо на екран значення змінної $privKey (в методі get_keys() я тимчасово повертаю значення закритого ключа):

Ось що ми побачимо на екрані:

Шифрування відкритим і закритим ключем

Потім зберігаємо отриманий ключ у текстовий файл.

$fpr = fopen(«private.txt»,»w»);
fwrite($fpr,$privKey);
fclose($fpr);

Тепер якщо ще раз оновити скрипт, то ми побачимо що створився текстовий файл в якому збережено закритий ключ. Далі необхідно згенерувати відкритий ключ. Для цього створимо запит сертифіката – CSR (Certificate Signing Request). Який являє собою зашифрований текст, що містить інформацію про компанії, доменному імені і т. д. Даний запит необхідний для придбання SSL сертифікату, який видається центром сертифікації. Що б створити запит CSR, необхідно створити масив з наступними даними:

$arr = array(
«countryName» => «UA»,
«stateOrProvinceName» => «Kievskaya Oblast»,
«localityName» => «Kiev»,
«organizationName» => «Organization»,
«organizationalUnitName» => «Soft»,
«commonName» => «localhost»,
«emailAddress» => «[email protected]»
);

Де:

«countryName» => «UA» – двозначний код країни;

«stateOrProvinceName» => «Kievskaya Oblast» – регіон чи область;

«localityName» => «Kiev»- місто;

«organizationName» => «Organization» – ім’я компанії;

«organizationalUnitName» => «Soft» – назва відділу;

«commonName» => «localhost» – доменне ім’я;

«emailAddress» => [email protected] – поштову адресу.

Далі створюємо запит CSR:

$csr = openssl_csr_new($arr,$privKey);

Зверніть увагу, що необхідно передати функції openssl_csr_new(), раніше створений масив і закритий ключ. Далі створюємо сертифікат:

$cert = openssl_csr_sign($csr,NULL, $privKey,10);
openssl_x509_export($cert,$str_cert);

Функція openssl_csr_sign – повертає дескриптор створеного сертифіката. Їй необхідно передати наступні параметри: $csr — запит csr, NULL – означає, що отриманий сертифікат буде самостійно згенерованим сертифікатом, $privKey – закритий ключ, 10 – час актуальності сертифіката в днях. Функція openssl_x509_export() – витягне з дескриптора $cert сертифікат і збереже його в змінній $str_cert. Далі, генеруємо відкритий ключ:

$public_key = openssl_pkey_get_public($str_cert);
$public_key_details = openssl_pkey_get_details($public_key);
$public_key_string = $public_key_details[‘key’];

Функція openssl_pkey_get_public() повертає дескриптор відкритого ключа (на основі здобутого раніше сертифіката), а функція openssl_pkey_get_details() повертає масив, у якому в комірці key, міститься відкритий ключ. Давайте подивимося, як він виглядає:

Шифрування відкритим і закритим ключем

Далі записуємо відкритий ключ у файл і повертаємо масив з отриманими ключами:

$fpr1 = fopen(«public.txt»,»w»);
fwrite($fpr1,$public_key_string);
fclose($fpr1);
return array(‘private’=>$privKey,’public’=>$public_key_string);

Шифрування даних

Для шифрування даний додамо метод my_enc():

public function my_enc($str) {
$path = «public.txt»;
$fpr = fopen($path,»r»);
$pub_key = fread($fpr,1024);
fclose($fpr);
openssl_public_encrypt($str,$result,$pub_key);
return $result;
}

Як Ви бачите, тут ми читаємо відкритий ключ з текстового файлу і викликаємо функцію openssl_public_encrypt(), яка шифрує дані відкритим ключем. Параметри, який необхідно передати їй: $str – рядок для шифрування; $result – змінна в яку будуть зберігатися результати і $pub_key – публічний ключ.

Дешифрування даних

Як завжди створюємо новий метод:

public function my_dec($str) {
$path = «private.txt»;
$fpr = fopen($path,»r»);
$pr_key = fread($fpr,1024);
fclose($fpr);
openssl_private_decrypt($str,$result,$pr_key);
return $result;
}

Першим ділом отримуємо закритий ключ з текстового файлу і викликаємо функцію openssl_private_decrypt(), яка розшифровує дані закритим ключем. Параметри, які необхідно передати їй $str – рядок для дешифрування, $result змінна в яку буде збережений результат, $pr_key – закритий ключ.

Перевірка роботи скрипта

Тепер давайте допишемо код файлу index.php, а саме створимо рядок для шифрування і викличемо послідовно методи my_enc(), для шифрування і my_dec() для дешифрування (наведу повний код файлу index.php):