Реализация RSA-шифрования методами Javascript и PHP

в 8:38, , рубрики: javascript, php, rsa, безопасность данных, передача данных

Здравствуйте друзья! Вот наконец то и я добрался до Хабра ресурса! Сразу скажу, я далеко не профессионал, и отношу себя скорее к разряду чайников, но если я поставил себе цель, я стараюсь ее реализовывать любым путем, даже если поставленная задача порой пугает меня. К чему это я? К тому что, этот Tutorial скорее для чайников, которые хотят реализовать простейшее асинхронное шифрование данных и посмотреть, как это работает, нежели для профи, которые пишут статьи, которые новичку сложно понять, не говоря уже о повторении и реализации готовой составляющей!

Небольшое отступление. Собственно говоря к чему вообще весь этот пост, спросите вы? Этот пост к тому, что пытаясь понять как работает RSA шифрование, я ни где не смог найти более понятного и короткого кода, для понимания «что вообще происходит». Блуждая по просторам всемирной паутины в поисках разъяснения, по методу "разжевал и положил в рот", я ни где ни смог найти внятного разъяснения, о таком сложном принципе работы как RSA шифрование. Конечно же в поиске знаний я всегда натыкался на Хабр-статьи. Здесь очень много чего написано, но на уровне Профи, на уровне чайника, это выглядело примерно так, как когда я захотел сделать свое RSA шифрование, открыл encrypt.js и с ужасом закрыл его, вспомнив поговорку программиста про велосипед. Я подумал: «Да, не стоит!».

В итоге, поиски не прошли даром и у меня получилось собрать все воедино, написать небольшой код для реализации RSA шифрования, что бы попробовать его в деле и понять, как это все работает.

Скомпилировав свои знания, я как можно проще старался реализовать проект, что бы каждый начинающий веб разработчик смог его повторить.

Итак, начнем друзья!

Совсем недавно, при разработке своего движка, я дошел до этапа безопасности передачи данных.
Может это я такой ненормальный, но меня до паники волнует этот вопрос.mПерерыл все, конечно же не обошел стороной и Хабр.

Задача была следующая, передать зашифрованные данные клиента→сервер, а на стороне сервера расшифровать их. Всe!

В принципе ничего сложного, но кто читал про Алису и Боба в wikipedia знают, что при передачи данных по незащищенному протоколу http, когда Алиса отправляет письмо Бобу, между ними может сидеть Ева, перехватывать это письмо и читать его. Наиболее детально я прочитал про это здесь.

В качестве локального сервера я использовал OpenServer.

Важно!

Настройки сервера:

— Apache 2.4
— PHP-5.5

Зачем и почему, об этом чуть ниже, а пока настроили и поехали дальше! Качаем jQuery. Качаем JSencrupt. Делаем все удобно и красиво, мы же хотим, что было все было «как по полочкам разложено». Создаем папку js в корне сайта, и кидаем туда скаченные jquery-3.2.0.min.js и jsencrypt.js.

Создаем папку system, а в ней файл decode.php, который будет декодировать кодированное сообщение и возвращать нам, показывая что все работает. На деле нам это конечно не нужно, ведь наша задача отправить зашифрованное сообщение на сервер, дешифровать его там и работать уже с дешифрованными данными, но сначала нужен приватный и публичный ключ.

Я заранее сгенерировал пару ключей:

rsa_2048_priv.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA9vWm5GzW1kUlDuZaQYB8o2zu4cp8YiTJnyQd5Gb4A2wVt3XK
Bu+4qLi1hd/6o9PMu9FB6rM64LrN2z3dWA+hBcXU5V1YRvCq5IBK3nTWI1KkRew3
UIQqOMYVhIrXDQcgpmmIu8GprJKsh5tdPTI8EJe/Bwezw89czaGTmXsNi5C1YEJn
zK3v8mifBuozNTnCMGZ7tHLSyS+SKyhY3EO1iN7WcTM7PcXbncCQWea4cykZvMg+
vx331aAUpS7gauWAjQvMIqQe9+txuUQiErs3gtvVzl3QyiVLuOnaxn5VoYyZse4p
QIW4OV5a4lQrJR0zWYBx4hmuM3VzPiQI1l+3TQIDAQABAoIBAB4flL3kMMhuIrkQ
jA3VWF6u2OydwFJQXm+U/jhv/uyb8IIyUfRKpWGfNjUgPvhgy2ZVfg7c0d+7qYSG
pUsqjN+hY/ieTDhK/u1kYL2FzuD8IaGN0Kl3lZbbQqCqNtUV+3uQ/+a3FrVAJt9b
qiHe0MjNWbXH0LufvZgvj0t3YQ2W2dDgqT+7IBj62YIx2fhutZAu1kYSFIbhelQr
h/Hhbw6AViLSVdJoj/wnfZKdWplbKcy9JgcKFE3FYnzX2I/zQsnzdefF0MpX0p4R
JK07J/sqc4Tmt25GrYHh+dy27m+XD7350d1LuYkImfdN7Ypd6Pm+vFOLGVRDmih/
qWlY1tkCgYEA/hV37itK654AqNHNwvzhG9tG2VO/UV7qrHQJ+tnHE+833fT/n+IR
wq0PEpbl7ZI6UffcqHmZ+kXWtH/t5bBpAWc4XFT208nyenf0DshIE2EU4Qjp81YH
AdE+k9uOG5hnytg63UXaPPRAL0G3eAgpauBnFhdEEev1kdhVZhqojE8CgYEA+NJt
6/GQHLqISlVIoE+jVHNXZ88LbKH9ox3bLVof3BQA36lXIgcFCqJxhBlfzQiWCWvt
WxXL35eL4ZRNbHv7KPbe5+sFFeLz4BLB7c+MBFqS7VzKYiEbzDmJ+u9Eq1HrH0Ly
AUNxCwiWjHiV4i3Qg4EdQ2GOzzfHJwPBYW+eT6MCgYA+CP3UH6vWJSiiDz9+qQFJ
LNt6elEOy+7eFiLNpVhOzKxGO+ghoC+X6WrxrfgLbhVhJ/QvCimHCoAmZ8mst8qb
dhkzqebtxLO4JQtohIvcd2qCmwuLxuhFEFKIBSYIJMjKpMqSddiX40a8gv4Jh2yd
VJa2tQ2AlqzJZBlNqZqXTwKBgQDjUFrbknP1yvN39THEQv0TycuwKpZlSBhPTJdP
d2ZjyGKD8lCH5aHVdVH/PK8owQ9QzCirbd4zBl/kVXfmA94QLni1px+ePxhNPNWu
TE2+LIDOGFdMDrM2f9puROiXGt+ST7aHMPW0/sOK0R8c4n37pZj2VcoBxRNLsUKZ
oT8fwQKBgQDOTq20saBbZzhOi6CCPAEu7dTCpPel2fo62uRwmenLaFvQ639wvXXB
UE9XApN3GQVwDe9qENZdc2FfF4WepexU4XRVdThIo6q/iBQhf/FvEai8WUGr1mhs
1IiCxAJur7Dc1Wk7niiCBgBWrZVART2Rp36atAog1ATdxwEHMyPmkg==
-----END RSA PRIVATE KEY-----

rsa_2048_pub.pem

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9vWm5GzW1kUlDuZaQYB8
o2zu4cp8YiTJnyQd5Gb4A2wVt3XKBu+4qLi1hd/6o9PMu9FB6rM64LrN2z3dWA+h
BcXU5V1YRvCq5IBK3nTWI1KkRew3UIQqOMYVhIrXDQcgpmmIu8GprJKsh5tdPTI8
EJe/Bwezw89czaGTmXsNi5C1YEJnzK3v8mifBuozNTnCMGZ7tHLSyS+SKyhY3EO1
iN7WcTM7PcXbncCQWea4cykZvMg+vx331aAUpS7gauWAjQvMIqQe9+txuUQiErs3
gtvVzl3QyiVLuOnaxn5VoYyZse4pQIW4OV5a4lQrJR0zWYBx4hmuM3VzPiQI1l+3
TQIDAQAB
-----END PUBLIC KEY-----

Но вы конечно же захотите сгенерировать свои:

В OpenServer на флажке, правой кнопкой мышки → Дополнительно → Консоль → Запускаем.

Для 2048 bit-ного ключа создаем приватный ключ, соответственно если нужно более меньший bit-ый ключ, ставим вместо значений 2048, например 512, и так копируем и вставляем в CMD:

openssl genrsa -out rsa_2048_priv.pem 2048

Для просмотра ключа, копируем и вставляем в CMD:

cat rsa_2048_priv.pem

Создаем публичный ключ, копируем и вставляем в CMD:

openssl rsa -pubout -in rsa_2048_priv.pem -out rsa_2048_pub.pem

Смотрим публичный ключ, копируем и вставляем в CMD:

cat rsa_2048_pub.pem

Все созданные ключи у меня появились в корне папки с программой OpenServer, так что если захотите снова посмотреть созданные приватные и публичные ключи, ищите их там.

Все теперь мы научились сами генерировать свои ключи, теперь приступим к кодингу! В созданном ранее файле decode.php пишем следующее:

$pk = '-----BEGIN RSA PRIVATE KEY-----//ключ который никто не должен знать
MIIEpAIBAAKCAQEA9vWm5GzW1kUlDuZaQYB8o2zu4cp8YiTJnyQd5Gb4A2wVt3XK
Bu+4qLi1hd/6o9PMu9FB6rM64LrN2z3dWA+hBcXU5V1YRvCq5IBK3nTWI1KkRew3
UIQqOMYVhIrXDQcgpmmIu8GprJKsh5tdPTI8EJe/Bwezw89czaGTmXsNi5C1YEJn
zK3v8mifBuozNTnCMGZ7tHLSyS+SKyhY3EO1iN7WcTM7PcXbncCQWea4cykZvMg+
vx331aAUpS7gauWAjQvMIqQe9+txuUQiErs3gtvVzl3QyiVLuOnaxn5VoYyZse4p
QIW4OV5a4lQrJR0zWYBx4hmuM3VzPiQI1l+3TQIDAQABAoIBAB4flL3kMMhuIrkQ
jA3VWF6u2OydwFJQXm+U/jhv/uyb8IIyUfRKpWGfNjUgPvhgy2ZVfg7c0d+7qYSG
pUsqjN+hY/ieTDhK/u1kYL2FzuD8IaGN0Kl3lZbbQqCqNtUV+3uQ/+a3FrVAJt9b
qiHe0MjNWbXH0LufvZgvj0t3YQ2W2dDgqT+7IBj62YIx2fhutZAu1kYSFIbhelQr
h/Hhbw6AViLSVdJoj/wnfZKdWplbKcy9JgcKFE3FYnzX2I/zQsnzdefF0MpX0p4R
JK07J/sqc4Tmt25GrYHh+dy27m+XD7350d1LuYkImfdN7Ypd6Pm+vFOLGVRDmih/
qWlY1tkCgYEA/hV37itK654AqNHNwvzhG9tG2VO/UV7qrHQJ+tnHE+833fT/n+IR
wq0PEpbl7ZI6UffcqHmZ+kXWtH/t5bBpAWc4XFT208nyenf0DshIE2EU4Qjp81YH
AdE+k9uOG5hnytg63UXaPPRAL0G3eAgpauBnFhdEEev1kdhVZhqojE8CgYEA+NJt
6/GQHLqISlVIoE+jVHNXZ88LbKH9ox3bLVof3BQA36lXIgcFCqJxhBlfzQiWCWvt
WxXL35eL4ZRNbHv7KPbe5+sFFeLz4BLB7c+MBFqS7VzKYiEbzDmJ+u9Eq1HrH0Ly
AUNxCwiWjHiV4i3Qg4EdQ2GOzzfHJwPBYW+eT6MCgYA+CP3UH6vWJSiiDz9+qQFJ
LNt6elEOy+7eFiLNpVhOzKxGO+ghoC+X6WrxrfgLbhVhJ/QvCimHCoAmZ8mst8qb
dhkzqebtxLO4JQtohIvcd2qCmwuLxuhFEFKIBSYIJMjKpMqSddiX40a8gv4Jh2yd
VJa2tQ2AlqzJZBlNqZqXTwKBgQDjUFrbknP1yvN39THEQv0TycuwKpZlSBhPTJdP
d2ZjyGKD8lCH5aHVdVH/PK8owQ9QzCirbd4zBl/kVXfmA94QLni1px+ePxhNPNWu
TE2+LIDOGFdMDrM2f9puROiXGt+ST7aHMPW0/sOK0R8c4n37pZj2VcoBxRNLsUKZ
oT8fwQKBgQDOTq20saBbZzhOi6CCPAEu7dTCpPel2fo62uRwmenLaFvQ639wvXXB
UE9XApN3GQVwDe9qENZdc2FfF4WepexU4XRVdThIo6q/iBQhf/FvEai8WUGr1mhs
1IiCxAJur7Dc1Wk7niiCBgBWrZVART2Rp36atAog1ATdxwEHMyPmkg==
-----END RSA PRIVATE KEY-----'
$data = $_POST['data'];//получаем шифрованный текст
$ogp = openssl_get_privatekey($pk);
if(@openssl_private_decrypt(base64_decode($data), $out, $ogp))echo $out;//если все прошло успешно выводим дешифрованные данные

Далее создадим в папке /js, файл script.js в котором напишем обработчик кнопки:

$(document).ready(function(){ //дожидаемся загрузки документа
$('#btn').click(function(){ //кликаем по кнопке
    var pub = '-----BEGIN PUBLIC KEY----- //присваиваем переменной публичный ключ
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9vWm5GzW1kUlDuZaQYB8
    o2zu4cp8YiTJnyQd5Gb4A2wVt3XKBu+4qLi1hd/6o9PMu9FB6rM64LrN2z3dWA+h
    BcXU5V1YRvCq5IBK3nTWI1KkRew3UIQqOMYVhIrXDQcgpmmIu8GprJKsh5tdPTI8
    EJe/Bwezw89czaGTmXsNi5C1YEJnzK3v8mifBuozNTnCMGZ7tHLSyS+SKyhY3EO1
    iN7WcTM7PcXbncCQWea4cykZvMg+vx331aAUpS7gauWAjQvMIqQe9+txuUQiErs3
    gtvVzl3QyiVLuOnaxn5VoYyZse4pQIW4OV5a4lQrJR0zWYBx4hmuM3VzPiQI1l+3
    TQIDAQAB-----END PUBLIC KEY-----',//переносы строк отделяем обратным слешем
    crypt = new JSEncrypt();//создаем объект JSEncrypt
    crypt.setPublicKey(pub);//устанавливаем публичный ключ
    var data = $('#data').val(),//считываем введенные данные с #data
         data = crypt.encrypt(data);//шифруем данные
    $.ajax({передаем данные методом Ajax
        url: '/system/decode.php',
        type: 'post',
        dataType: 'text',
        data: {data: data},
        success: function(a){
           if(a){//если данные пришли вписываем их в поля #encrypted и #reply
              $('#encrypted').val(data);//шифрованные данные на сервер
              $('#reply').val(a);//дешифрованные данные с сервера
           }
        }
    });
});
});

Создаем файл в корне сайта index.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
 <head>
    <script type="text/javascript" src="js/jquery-3.2.0.min"></script>
    <script type="text/javascript" src="js/jsencrypt.js"></script>
    <script type="text/javascript" src="js/script.js"></script>
</head>
<body>
<input id="data" style="width: 120px; height: 30px; margin-bottom:5px; font-size: 21px;" placeholder="Данные:"/>
<input id="encrypted" style="width: 100%; height: 30px; margin-bottom:5px; background-color: white; border: 1px solid gray; font-size: 21px;" placeholder="Данные на сервер:"/>
<input id="reply" style="width: 100%; height: 30px; margin-bottom:5px; background-color: white; border: 1px solid gray; font-size: 21px;" placeholder="Ответ Сервера:"/>
<div id="btn" style="width: 120px; height: 30px; border: 1px solid gray; margin-bottom:5px; cursor: pointer; background-color: gray; color: white; font-size: 21px; text-align: center; border-radius: 3px;">Отправить</div>
</body>
</html>

С какими трудностями пришлось столкнуться?

Как я писал выше, важно правильно настроить OpenServer. Из за того, что у меня стояли настройки сервера:

— Apache 2.2
— PHP-5.3

Apache рушился с ошибкой:

Прекращена работа программы Apache HTTP Server

Сигнатура проблемы:
Имя события проблемы: APPCRASH
Имя приложения: httpd.exe
Версия приложения: 2.2.31.0
Отметка времени приложения: 55a77942
Имя модуля с ошибкой: LIBEAY32.dll
Версия модуля с ошибкой: 1.0.1.16
Отметка времени модуля с ошибкой: 55a2477e
Код исключения: c0000005
Смещение исключения: 000409ab
Версия ОС: 6.1.7601.2.1.0.256.1
Код языка: 1049
Дополнительные сведения 1: 0a9e
Дополнительные сведения 2: 0a9e372d3b4ad19135b953a78882e789
Дополнительные сведения 3: 0a9e
Дополнительные сведения 4: 0a9e372d3b4ad19135b953a78882e789

Если закомментировать функцию openssl_private_decrypt(), то Apache не рушился, наверно из за нее, не зря эта функция не задокументирована, как пишут в справочниках по php «вы ее используете на свой страх и риск»!

Еще важно знать! Как я прочитал тут на Хабре, что при ключе 512-bit, мы можем зашифровать 53 байта, как я понимаю это можно использовать 53 символа, например если вы в поля для ввода пароля задали максимальную длину 60 и пользователь ввел все 60 символов, то произойдет ошибка. Если я не прав, поправьте меня в комментариях пожалуйста.

На этом все друзья, конечно статья не раскрыла все секреты RSA шифрования, но надеюсь она помогла тем, кто не мог понять принцип ее работы и тем кто хотел реализовать несложную, безопасную передачу данных.

Всем защиты и безопасной передачи данных, уважаемые Хабровчане!

Автор: djasonx

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js