Ассиметричный алгоритм криптографии RSA, датой возникновения концепции которого считается 1976 год сейчас очень активно используется для обмена данными, верификацией источника программного обеспечения и в других сферах, где необходимо обмениваться данными или верифицировать отправителя. Кроме того, он является базовой частью HTTPS протокола, использование которого в России достигло 98% по данным Яндекс. Радара
.
Например, звоня любимой бабушке через популярный мессенджер или вводя данные своей банковской карточки в онлайн маркетплейсе, перед обменом видеоизображением или данными банковской карты, происходит процедура проверки подлинности и обмена ключом шифрования по алгоритму RSA.
Но что же это за алгоритм такой и как он работает? В этой статье я постараюсь разложить по полочкам основные принципы его работы и ассиметричной криптографии в целом.
- RSA ключи и шифрование данных
- Подпись данных и цепочка доверия
- Компрометация ключей и списки отзыва
- Под капотом
- Заключение
- Как самостоятельно изготовить электронную подпись
- Что такое электронная подпись
- Генерирование открытого и секретного ключей
- Подписание документа
- Проверка подписи
- Введение
- Что потребуется для работы
- Генерация ключей
- Шифрование данных
- Дешифрование данных
- Проверка работы скрипта
- Установка GPG
- Использование
- Создание ключа
- Конфигурация
- Команды и опции
- Редактирование ключа, подпись чужих ключей и отправка ключа на сервер ключей
- Где вы можете столкнуться с использованием GPG
- Ссылки
RSA ключи и шифрование данных
В отличии от симметричных алгоритмов шифрования, имеющих всего один ключ для шифрования и расшифровки информации, в алгоритме RSA используется 2 ключа – открытый (публичный) и закрытый (приватный).
Публичный ключ шифрования передаётся по открытым каналам связи, а приватный всегда держится в секрете. Но зачем нужно целых два ключа и как они работают?
В ассиметричной криптографии и алгоритме RSA, в частности, публичный и приватный ключи являются двумя частями одного целого и неразрывны друг с другом. Для шифрования информации используется открытый ключ, а для её расшифровки приватный.
Предположим, Боб хочет передать Алисе какое-то сообщение, но лично он это сделать не может, поэтому ему необходимо использовать посредника, например Стива. Однако Боб передаёт Алисе информацию про сюрприз для Стива на его день рождения, так что не может допустить, чтобы Стив это сообщение увидел. И тут ему пригодится протокол RSA.
Перед обменом сообщением, Боб просит у Алисы её открытый ключ
После получения ключа, переданного через Стива, Боб шифрует своё сообщение ключом Алисы
Далее Боб, через Стива, передаёт Алисе зашифрованное сообщение
Алиса расшифровывает сообщение своим закрытым ключом
Таким образом, Стив видел открытый ключ Алисы и зашифрованное сообщение от Боба, но без закрытого ключа Алисы это сообщение не расшифровать. То есть, пусть Стив и держал в руках все передаваемые данные, но он не может узнать, что Боб передал Алисе!

Вы можете задаться вопросом, а почему Стив не может подменить ключ Алисы на свой, расшифровать сообщение, а потом, подглядев его, зашифровать обратно на ключ Алисы? Ещё как может, это называется атака «человек посередине» (Man in the middle (MITM)), и выглядит она следующим образом:

Но есть ли решение этой проблемы? Да! Chain of Trust, или «Цепочка доверия»
Подпись данных и цепочка доверия
Перед тем как разбирать что такое «Цепочка доверия», нужно знать про ещё одну возможность закрытого ключа – подпись информации. Она осуществляется с помощью закрытого ключа и проверяется открытым.
То есть, если Боб и Алиса заранее обменялись своими открытыми ключами, они могут писать друг другу сообщения и прикреплять к ним некий набор данных. Если взять этот набор данных, открытый ключ и само сообщение, можно проверить действительно ли сообщение было отправлено собеседником и не подменил ли его кто-то по дороге.

С функцией подписи закрытого ключа разобрались, действительно полезная штука! Но как это решает проблему человека по середине, ведь если Боб и Алиса не могут без посредников обменяться открытыми ключами, Стив может подменить их при передаче и постоянно перехватывать сообщения?
А всё просто! Поскольку, с помощью закрытого ключа можно подписать какие-то данные, с его помощью можно подписать и сам открытый ключ.
Если есть кто-то, предположим Грант, которому Боб и Алиса могут доверять и чей открытый ключ у них уже есть, то Грант может подписать их открытые ключи. Таким образом, если Стив попытается подменить открытый ключ Алисы, которая посылает его Бобу, то Боб сразу обнаружит подмену, ведь на ключе не будет подписи Гранта.
Также Грант может подписать открытый ключ Марку, который подпишет открытые ключи Боба и Алисы, создав таким образом ту самую «цепочку доверия».
В реальном мире существуют доверенные корневые центры сертификации (Грант), промежуточные центры (Марк) и конечные получатели (Боб и Алиса).

Компрометация ключей и списки отзыва
А теперь предположим, что Алиса оставила на виду свой закрытый ключ, его увидел Стив и теперь может подписывать любые сообщения, а также перехватывать и расшифровывать все данные, которые шифруются на открытый ключ Алисы. Такая проблема называется «Компрометация ключа».
На такой случай, умные люди придумали «список отзыва» (Certificate Revocation List (CRL)), в котором будут публиковаться скомпрометированные ключи, к которым больше нет доверия.
Адрес, где находится такой список отзыва встроен во все сертификаты корневых и промежуточных центров сертификации. То есть, если Алиса заподозрит, что Стив увидел её закрытый ключ, она должна будет немедленно сказать от этом Марку, который опубликует номер её сертификата в своём списке отзыва. Боб со своей стороны, при получении старого сертификата, которым попытается воспользоваться Стив, найдёт запись о его отзыве в списке Марка и будет понимать, что Алиса была скомпрометирована и доверять её старому сертификату уже нельзя.

Под капотом
С базовыми аспектами RSA алгоритма разобрались, теперь давайте заглянем «под капот» и посмотрим, как работает эта магия.
Вся ассиметричная криптография держится на принципе «в одну сторону быстро, в другую неразумно долго».
Например, если мы перемножим числа 592939 и 592967 мы получим число 351593260013. Но как имея только число 351593260013 узнать числа 592939 и 592967? А если каждое из этих двух чисел будут длиной более 1000 знаков? Это называется «сложность задачи факторизации произведения двух больших простых чисел
», т.е. в одну сторону просто, а в обратную невероятно сложно.

Теперь рассмотрим процедуру создания публичного и приватного ключей:
Выбираем два случайных простых числа p и q
Вычисляем их произведение: N = p * q
Вычисляем функцию Эйлера
:
(N) = (p-1) * (q-1)Выбираем число e (обычно простое, но необязательно), которое меньше
(N) и является взаимно простым с
(N) (не имеющих общих делителей друг с другом, кроме 1).Ищем число d, обратное числу e по модулю
(N) . Т.е. остаток от деления (d*e) и
(N) должен быть равен 1. Найти его можно через расширенный алгоритм Евклида
(под спойлером)
Расширенный алгоритм Евклида

Где a =
(N), b = e
После вычисления x2 и y2 вычисляем d по простой формуле, где x — меньшее из этих двух чисел
После произведённый вычислений, у нас будут:
e и n – открытый ключ
d и n – закрытый ключ
А теперь создадим эти ключи на примере малых простых чисел:
Пусть p = 19, q = 41
Ключи мы с вами вычислили, теперь перейдём к шифрованию сообщений.
Предположим, что Боб спрашивает у Алисы во сколько сегодня вечеринка. Алиса знает, что вечеринка в 21, но что ей нужно сделать чтобы передать это Бобу так, чтобы Стив об этом не узнал?

Заключение
Мы рассмотрели основные аспекты криптографического алгоритма RSA, однако многое осталось за кадром, надеюсь у меня получилось достаточно понятно объяснить, как это работает даже тем, кто очень далёк от криптографии и подобных вещей.
Также рекомендую почитать пару интересных статей на тему криптографии от коллег с Хабра:
Первые несколько миллисекунд HTTPS соединения
– про то, как работает криптография работает на сайтах
Доступно о криптографии на эллиптических кривых
— альтернатива RSA
Полное руководство по переходу с HTTP на HTTPS
– о том как настроить HTTPS у себя на сайте
Let’s Encrypt выдал миллиард сертификатов
– о том как Let’s Encrypt помогает обезопасить интернет
Как самостоятельно изготовить электронную подпись
Оговорюсь сразу — я почти дилетант в вопросах, связанных с электронной цифровой подписью (ЭЦП). Недавно, движимый естественным любопытством, я решил немного разобраться в этом и нашел в Интернете 100500 статей на тему получения сертификатов ЭЦП в различных удостоверяющих центрах, а также многочисленные инструкции по использованию различных готовых приложений для подписания документов. Кое-где при этом вскользь упоминалось, что неквалифицированную подпись можно изготовить самостоятельно, если воспользоваться услугами «опытного программиста».
Мне тоже захотелось стать хоть немного «опытным» и разобраться в этой кухне изнутри. Для интереса я научился генерировать PGP-ключи, подписывать документы неквалифицированной подписью и проверять ее достоверность. Понимая, что никакой Америки не открыто, я, тем не менее, предлагаю этот краткий туториал для таких же, как и я, дилетантов в вопросах работы с ЭЦП. Я постарался особо не углубляться в теорию и в детали, а написать именно небольшое и краткое введение в вопрос. Тем, кто уже работает с ЭЦП, это вряд ли будет интересно, а вот новичкам, для первого знакомства — в самый раз.
Что такое электронная подпись
Все термины и определения приведены в законе
, поэтому изложим всё, как говорится, своими словами, не претендуя при этом на абсолютную юридическую точность формулировок.
Электронная цифровая подпись (ЭЦП)
— это совокупность средств, позволяющих однозначно удостовериться в том, что автором документа (или исполнителем какого-то действия) является именно то лицо, которое называет себя автором. В этом смысле ЭЦП полностью аналогична традиционной подписи: если в обычном «бумажном» документе указано, что его автор Иванов, а внизу стоит подпись Петрова, вы справедливо можете усомниться в авторстве Иванова.
Мне однажды встречался такой способ удостоверения подлинности электронных документов в одной организации: перед рассылкой документа изготавливался его хэш
и подписывался в базу хэшей (обычный текстовый файл, лежащий на сервере). Далее любой желающий удостовериться в подлинности электронного документа заходил на официальный сайт этой организации (в официальности которого ни у кого сомнений не возникало) и с помощью специального сервиса проверял, содержится ли хэш проверяемого документа в базе. Замечательно при этом, что сам документ даже не нужно было загружать на сервер: хэш можно вычислить на клиентской стороне в браузере, а на сервер послать только маленький fetch- или ajax-запрос с этим хэшем. Безусловно, этот немудрёный способ можно с полным основанием назвать простой ЭЦП: подписью в данном случае является именно хэш документа, размещенный в базе организации.
Поговорим теперь об усиленной
электронной подписи. Она предполагает использование стандартных криптографических алгоритмов; впрочем, таких алгоритмов существует достаточно много, так что и здесь единого стандарта нет. Тем не менее де-факто усиленная ЭЦП обычно основана на асимметричном шифровании
(абсолютно гениальном, на мой взгляд, изобретении Ральфа Меркла
), идея которого чрезвычайно проста: для шифрования и расшифровывания используются два разных ключа
. Эти два ключа всегда генерируются парой; один называется открытым ключом
(public key), а второй — секретным ключом
(private key). При этом, имея один из двух ключей, второй ключ воспроизвести за разумное время невозможно.
Представим себе, что Аня хочет послать Боре (почему в литературе по криптографии обычно фигурируют Алиса и Боб? пусть будут Аня и Боря) секретную посылочку, закрытую на висячий замочек, и при этом на почте работают злые люди, которые хотят эту посылочку вскрыть. Других каналов связи, кроме почты, у Ани и Бори нет, так что ключ от замочка Аня передать Боре никак не может. Если она пошлет ключ по почте, то злые люди его, конечно, перехватят и вскроют посылочку.
Ситуация кардинально меняется, если изобретен замок с двумя ключами
: один только для закрывания, а второй — только для открывания. Боря генерирует себе пару таких ключей (открытый и секретный) и открытый ключ шлет по почте Ане. Работники почты, конечно, потирая руки, делают себе копию этого ключа, но не тут-то было! Аня закрывает замок на посылке открытым ключом Бори и смело идет на почту. Работники почты вскрыть посылку открытым ключом не могут (он использовался для закрывания
), а Боря спокойно открывает ее своим секретным ключом, который он бережно хранил у себя и никуда не пересылал.
Вернемся к усиленной электронной подписи. Предположим, некий Иван Иванович Иванов захотел подписать документ с помощью ЭЦП. Он генерирует себе два ключа: открытый и секретный. После этого изготавливает (стандартным способом) хэш документа и шифрует его с использованием своего секретного
ключа. Можно, конечно, было зашифровать и весь документ, но полученный в результате такого шифрования файл может оказаться очень большим, поэтому шифруется именно небольшой по размеру хэш.
Полученный в результате такого шифрования файл и будет являться усиленной электронной подписью.
Её еще называют отсоединенной
(detach), так как она хранится в отдельном от документа файле. Такой вариант удобен тем, что подписанный отсоединенной ЭЦП файл можно спокойно прочитать без какой-либо расшифровки.
Что же теперь отправляет Иван Иванович получателям? А отправляет он три файла: сам документ, его электронную подпись и открытый
ключ. Получатель документа:
- изготавливает его хэш с помощью стандартного алгоритма;
- расшифровывает электронную подпись, используя имеющийся у него открытый ключ Ивана Ивановича;
- убеждается, что хэш совпадает с тем, что указан в расшифрованной электронной подписи (то есть документ не был подменен или отредактирован). Вуаля!
Из этой коллизии существует два выхода. Первый, самый простой, заключается в том, что Иванов может разместить свой открытый ключ на своем персональном сайте (или на официальном сайте организации, где он работает). Если подлинность сайта не вызывает сомнений (а это отдельная проблема), то и принадлежность открытого ключа Иванову сомнений не вызовет. Более того, на сайте можно даже разметить не сам ключ, а его отпечаток
(fingerprint), то есть, попросту говоря, хэш открытого ключа. Любой, кто сомневается в авторстве Иванова, может сверить отпечаток ключа, полученного от Иванова, с тем отпечатком, что опубликован на его персональном сайте. В конце концов, отпечаток можно просто продиктовать по телефону (обычно это 40 шестнадцатеричных цифр).
Второй выход, стандартный, состоит в том, что открытый ключ Иванова тоже должен быть подписан электронной подписью — того, кому все доверяют. И здесь мы приходим к понятию усиленной квалифицированной
электронной подписи. Смысл ее очень прост: Иванов идет в специальный аккредитованный удостоверяющий центр
, который подписывает открытый ключ Иванова своей
электронной подписью (присоединив предварительно к ключу Иванова его персональные данные). То, что получилось, называется сертификатом открытого ключа
Иванова.
Теперь любой сомневающийся может проверить подлинность открытого ключа Иванова с помощью любого из многочисленных сервисов Интернета, то есть расшифровать его сертификат (онлайн, с помощью открытого ключа удостоверяющего центра) и убедиться, что ключ принадлежит именно Иванову. Более того, Иванову теперь достаточно послать своим корреспондентам только сам документ и его отсоединенную подпись (содержащую и сведения о сертификате): все необходимые проверки будут сделаны желающими онлайн.
Справедливости ради необходимо отметить, что и неквалифицированная ЭЦП может быть сертифицирована: никто не мешает какому-то третьему лицу (например, неаккредитованному удостоверяющему центру
) подписать открытый ключ Иванова своей ЭЦП и получить таким образом сертификат открытого ключа. Правда, если удостоверяющий центр не аккредитован, степень доверия к подписи Иванова будет полностью зависеть от степени доверия к этому центру.
Всё замечательно, да вот только услуги удостоверяющих центров по изготовлению для вас подписанных (снабженных сертификатом центра) ключей стоят денег (обычно несколько тысяч рублей в год). Поэтому ниже мы рассмотрим, как можно самостоятельно
изготовить усиленную ЭЦП (неквалифицированную, не снабженную сертификатом открытого ключа от аккредитованного удостоверяющего центра). Юридической силы (например, в суде) такая подпись иметь не будет, так как принадлежность открытого ключа именно вам никем не подтверждена, но для повседневной переписки деловых партнеров или для документооборота внутри организации эту подпись вполне можно использовать.
Генерирование открытого и секретного ключей
Итак, вы решили самостоятельно изготовить усиленную неквалифицированную электронную подпись и научиться подписывать ею свои документы. Начать необходимо, конечно, с генерирования пары ключей, открытого (public key) и секретного (private key).
Существует множество стандартов и алгоритмов асимметричного шифрования. Одной из библиотек, реализующих эти алгоритмы, является PGP (Pretty Good Privacy). Она была выпущена в 1991 году под проприетарной лицензией, поэтому имеются полностью совместимые с ней свободные библиотеки (например, OpenPGP). Одной из таких свободных библиотек является выпущенная в 1999 году GNU Privacy Guard (GnuPG, или GPG). Утилита GPG традиционно входит в состав почти всех дистрибутивов Линукса; для работы из-под Windows необходимо установить, например, gpg4win
. Ниже будет описана работа из-под Линукса.
Сначала сгенерируем собственно ключи, подав (из-под обычного юзера, не из-под root’а) команду
gpg --full-generate-key
В процессе генерирования вам будет предложено ответить на ряд вопросов:
- тип ключей можно оставить «RSA и RSA (по умолчанию)»;
- длину ключа можно оставить по умолчанию, но вполне достаточно и 2048 бит;
- в качестве срока действия ключа для личного использования можно выбрать «не ограничен»;
- в качестве идентификатора пользователя можно указать свои фамилию, имя и отчество, например,
Иван Иванович Иванов
; адрес электронной почты можно не указывать; - в качестве примечания можно указать город, либо иную дополнительную информацию.
После ввода вами всех запрошенных данных утилита GPG попросит вас указать пароль, необходимый для доступа к секретному ключу. Дело в том, что сгененрированный секретный ключ будет храниться на вашем компьютере, что небезопасно, поэтому GPG дополнительно защищает его паролем. Таким образом, не знающий пароля злоумышленник, даже если и получит доступ к вашему компьютеру, подписать документы от вашего имени не сможет.
Сгенерированные ключи (во всяком случае, открытый, но можно также и секретный, на тот случай, если ваш компьютер внезапно сломается) необходимо экспортировать в текстовый формат:
gpg --export -a "Иван Иванович Иванов" > public.key
gpg --export-secret-key -a "Иван Иванович Иванов" > private.key
Понятно, что private.key
вы должны хранить в секрете, а вот public.key
вы можете открыто публиковать и рассылать всем желающим.
Подписание документа
Нет ничего проще, чем создать отсоединенную ЭЦП в текстовом (ASCII) формате:
gpg -ba имя_подписываемого_файла
Файл с подписью будет создан в той же папке, где находится подписываемый файл и будет иметь расширение asc
. Если, например, вы подписали файл privet.doc
, то файл подписи будет иметь имя privet.doc.asc
. Можно, следуя традиции, переименовать его в privet.sig
, хотя это непринципиально.
Если вам не хочется каждый раз заходить в терминал и вводить руками имя подписываемого файла с полным путем, можно написать простейшую графическую утилиту для подписания документов, например, такую:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import *
from tkFileDialog import *
import os, sys, tkMessageBox
def die(event):
sys.exit(0)
root = Tk()
w = root.winfo_screenwidth()//2 - 400
h = root.winfo_screenheight()//2 - 300
root.geometry("800x600+{}+{}".format(w, h))
root.title("Подписать документ")
flName = askopenfilename(title="Что подписываем?")
if flName:
os.system("gpg -ba " + flName)
button = Button(text="ЭЦП создана")
button.bind("<Button-1>", die)
button.pack(expand=YES, anchor=CENTER)
else:
die()
root.mainloop()
Проверка подписи
Вряд ли, конечно, вам самому придется проверять достоверность собственной электронной подписи, но если вдруг (на всякий случай) вам захочется это сделать, то нет ничего проще:
gpg --verify имя_файла_подписи имя_файла_документа
В реальности гораздо полезнее опубликовать где-нибудь в открытом доступе (например, на вашем персональном сайте или на сайте вашей организации):
- открытый ключ
public.key
для того, чтобы все желающие могли проверить (верифицировать) вашу подпись с использованием, например, той же GPG; - веб-интерфейс для проверки вашей подписи всеми желающими, не являющимися специалистами.
Описанию такого веб-интерфейса (причем без использования серверных технологий, с проверкой подписи исключительно на клиентской стороне) и будет посвящена последняя часть моего краткого туториала.
К счастью для нас, имеется свободная библиотека OpenPGP.js
; скачиваем самый маленький по размеру (на момент написания данного туториала — 506 КБ) файл dist/lightweight/openpgp.min.js
и пишем несложную html-страничку (для упрощения восприятия я удалил все описания стилей и очевидные meta-тэги):
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body>
<label for="doc">Загрузите файл с документом</label>
<input id="doc" type="file" onChange="readDoc('doc')">
<label for="sig">Загрузите файл с подписью</label>
<input id="sig" type="file" onChange="readDoc('sig')">
<button type="button" disabled onClick="check()">Проверить</button>
<output></output>
<script src="openpgp.min.js"></script>
<script src="validate.js"></script>
</body>
</html>
Понятно, что файл с открытым ключом public.key
и файл библиотеки openpgp.min.js
должны лежать в той же папке, что и эта страничка.
Вся работа по верификации подписей будет производиться подключенным скриптом validate.js
:
"use strict";
let cont = {doc:'', sig:''},
flag = {doc:false, sig:false},
pubkey = '',
mess = '';
// Чтение файлов документа (как бинарного),
// ключа и подписи (как текстовых)
const readDoc = contKey => {
let reader = new FileReader();
reader.onload = async e => {
cont[contKey] = contKey == "sig" ?
e.target.result :
new Uint8Array(e.target.result);
flag[contKey] = true;
pubkey = await (await fetch("public.key")).text();
if (flag["doc"] && flag["sig"])
document.querySelector("button").disabled = false;
}
reader.onerror = err => alert("Ошибка чтения файла");
let fileObj = document.querySelector(`#${contKey}`).files[0];
if (contKey == "sig") reader.readAsText(fileObj);
else reader.readAsArrayBuffer(fileObj);
}
// Верификация подписи
const check = async () => {
try {
const verified = await openpgp.verify({
message: openpgp.message.fromBinary(cont["doc"]),
signature: await openpgp.signature.readArmored(cont["sig"]),
publicKeys: (await openpgp.key.readArmored(pubkey)).keys
});
const {valid} = verified.signatures[0];
mess = "Электронная подпись НЕ является подлинной!";
if (valid) mess = "Электронная подпись является подлинной.";
} catch(e) {mess = "Файл подписи имеет недопустимый формат.";}
document.querySelector("output").innerHTML = mess;
}
Вот, собственно, и всё. Теперь вы можете в соответствии с пунктом 5.23 ГОСТ 7.0.97–2016
разместить на документе (в том месте, где должна стоять собственноручная подпись) вот такую красивую картинку:
Введение
Хотел бы сразу отметить, что шифрование – это довольно сложная наука и конечно за один урок мы с Вами не сможем рассмотреть все досконально. Но, мы рассмотрим – основу, то есть, как реализовать механизм шифрования, используя открытый и закрытый ключ.
Итак, системы шифрования с открытым и закрытым ключом были придуманы еще в 70-х гг. То есть – это были системы, которые обеспечивающие передачу шифрованных сообщений, для расшифровки которых необходимо было использовать ключ, отличный от ключа шифрования. Это было главное отличие новых систем от старых, в которых использовался всего один ключ – для шифрования и расшифровки сообщения.
В системах шифрования с открытым ключом используется скрипт, шифрующий данные при помощи открытого ключа. Открытый ключ — это шифр, который непосредственно выступает инструкцией по шифрованию сообщения. Открытый ключ создается скриптом шифрования, и для каждого пользователя он свой — уникальный.
После того, как сообщение зашифровано, его можно расшифровать только при помощи закрытого ключа.
Обратите внимание на рисунок(выше) – это схема работы системы шифрования с открытым и закрытым ключом.
Итак, к примеру Вам необходимо отправить шифрованное сообщение определенному пользователю. Для начала необходимо получить открытый ключ от этого пользователя. Получив данный ключ, Вы используя скрипт шифрования – шифруете сообщение и отправляете его пользователю. Для дешифрования сообщений пользователь использует свой закрытый ключ. При этом для расшифровки сообщения уже нельзя воспользоваться открытым ключом. Это означает, что только получатель сообщения сможет прочитать сообщение, используя свой закрытый ключ.
Таким образом, закрытый ключ в сочетании со скриптом шифрования используется для дешифрования сообщения, зашифрованного при помощи открытого ключа пользователя. Без знания закрытого ключа дешифровать зашифрованный файл невозможно.
Что потребуется для работы
В сегодняшнем уроке для реализации механизма шифрования мы будем использовать расширение языка PHP – OpenSSL.
Вообще OpenSSL — это система защиты и сертификации данных. S SL переводится, как система безопасных сокетов (secure socket layer). OpenSSL используется практически всеми сетевыми серверами для защиты передаваемой информацией и это достаточно сложная и обширная система. В сегодняшнем уроке мы рассмотрим только те моменты, которые затрагивают шифрование данных.
Итак, первым делом необходимо подключить расширение OpenSSL в Вашем интерпретаторе языка PHP. Для этого необходимо открыть главный конфигурационный файл php.ini и раскомментировать строку (убрать символ ; сначала данной строки):
Теперь еще один момент: после установки пакета дополнительных расширений и собственно после раскомментирования строки, что указана выше – расширение openssl может так и не заработать. Для исправления данной проблемы необходимо открыть папку (на вашем локальном диске) usr\local\php5 и найти два файла: libeay32.dll и ssleay32.dll. Данные файлы необходимо скопировать и вставить в папку usr\local\apache\bin. В данной папке уже есть копии этих библиотек, но их версии отличаются, от библиотек которые находятся в интерпретаторе языка PHP (в папке usr\local\php5). После этого перезапускаем denwer и все должно работать. Вообще на реальном сервере – хостинге, данное расширение установлено и корректно настроено.
Генерация ключей
Итак, первым делом, необходимо сгенерировать ключи. Для этого мы создадим файл Enc.class.php и создадим класс, который будет являться логическим ядром нашего скрипта:
В данном в классе создаем статический метод get_keys(), который мы будем использовать для генерации ключей и сохранении их в текстовых файлах (подразумевается, что данный метод будет вызван всего одни раз – для генерации и записи ключей в текстовые файлы). Первым дело создаем массив, конфигов, то есть задаем настройки при создании закрытого ключа:
Указываем тип ключа OPENSSL_KEYTYPE_RSA (закрытый ключ для шифрования открытым и закрытым ключем) и размер в битах будущего ключа (512 бит). Далее генерируем закрытый ключ и возвращаем его дескриптор:
Вытащим значение ключа из его дескритпора:
Функция openssl_pkey_export() – возвращает закрытый ключ в виде строки и данная строка сохраняется в переменной $privKey, которая передается вторым аргументом данной функции. Первый параметр – это дескриптор ключа. Теперь давайте создадим файл index.php и выведем на экран значение переменной $privKey (в методе get_keys() я временно возвращаю значение закрытого ключа):
Вот что мы увидим на экране:
Затем сохраняем полученный ключ в текстовый файл.
Теперь если еще раз обновить скрипт, то мы увидим что создался текстовый файл в котором сохранен закрытый ключ. Далее необходимо сгенерировать открытый ключ. Для этого создадим запрос для сертификата – CSR (Certificate Signing Request). Который представляет собой зашифрованный текст, содержащий информацию о компании, доменном имени и т.д. Данный запрос необходим для приобретения SSL сертификата, который выдается центрами сертификации. Что бы создать запрос CSR, необходимо создать массив со следующими данными:
«countryName» => «UA» – двузначный код страны;
«stateOrProvinceName» => «Kievskaya Oblast» – регион или область;
«localityName» => «Kiev»- город;
«organizationName» => «Organization» – имя компании;
«organizationalUnitName» => «Soft» – название отдела;
«commonName» => «localhost» – доменное имя;
Далее создаем запрос CSR:
Обратите внимание, что необходимо передать функции openssl_csr_new(), ранее созданный массив и закрытый ключ. Дальше создаем сертификат:
Функция openssl_csr_sign – вернет дескриптор созданного сертификата. Ей необходимо передать следующие параметры: $csr- запрос csr, NULL – обозначает, что полученный сертификат будет самостоятельно сгенерированным сертификатом, $privKey – закрытый ключ, 10 – время актуальности сертификата в днях. Функция openssl_x509_export() – вытащит из дескриптора $cert сертификат и сохранит его в переменной $str_cert. Далее, генерируем открытый ключ:
Функция openssl_pkey_get_public() возвращает дескриптор открытого ключа (на основе полученного ранее сертификата), а функция openssl_pkey_get_details() возвращает массив, в котором в ячейке key, содержится открытый ключ. Давайте посмотрим, как он выглядит:
Далее записываем открытый ключ в файл и возвращаем массив с полученными ключами:
Шифрование данных
Для шифрования данный добавим метод my_enc():
Как Вы видите, здесь мы читаем открытый ключ из текстового файла и вызываем функцию openssl_public_encrypt(), которая шифрует данные открытым ключом. Параметры, который необходимо ей передать: $str – строка для шифрования; $result – переменная в которую будут сохранены результаты и $pub_key – публичный ключ.
Дешифрование данных
Как обычно создаем новый метод:
Первым делом получаем закрытый ключ из текстового файла и вызываем функцию openssl_private_decrypt(), которая дешифрует данные закрытым ключом. Параметры, которые необходимо ей передать $str – строка для дешифрования, $result переменная в которую будет сохранен результат, $pr_key – закрытый ключ.
Проверка работы скрипта
Теперь давайте допишем код файла index.php, а именно создадим строку для шифрования и вызовем последовательно методы my_enc(), для шифрования и my_dec() для дешифрования (приведу полный код файла index.php):
Теперь давайте посмотрим, что у нас получилось:
Как Вы видите все успешно отработало. На этом данный урок завершен. Всего Вам доброго и удачного кодирования!!!
Кратко о том, как создавать ключи, шифровать и подписывать файлы и отправлять ключи на сервер ключей.
GPG
(также известный как GnuPG) создавался как свободная альтернатива несвободному PGP
. G PG используется для шифрования информации и предоставляет различные алгоритмы (RSA, DSA, AES и др.) для решения этой задачи.
GPG может использоваться для симметричного шифрования, но в основном программа используется для ассиметричного шифрования информации. Если кратко — при симметричном шифровании для шифровки и расшифровки сообщения используется один ключ (например, какой символ соответствует той или иной букве). При ассиметричном шифровании используются 2 ключа — публичный и приватный. Публичный используется для шифрования и его мы можете дать своим друзьям, а приватный — для расшифровки, и его вы должны хранить в безопасности. Благодаря такой схеме расшифровать сообщение может только владелец приватного ключа (даже тот, кто зашифровывал сообщение, не может произвести обратную операцию). Подробнее про асимметричное шифрование вы можете прочитать в Википедии
.
Установка GPG
В большинстве дистрибутивов GNU/Linux GPG уже установлен. Если же он у вас не установлен, установите пакет gnupg
с помощью своего пакетного менеджера или соберите его из исходников
.
Для Android существуют программы GnuPG for Android и OpenKeychain. Создатели GnuPG for Android рекомендуют использовать OpenKeychain.
Официальный сайт OpenKeychain
OpenKeychain в F-Droid
OpenKeychain в Google Play
Официальный сайт GnuPG for Android
Исходники GnuPG for Android на GitHub
Спасибо товарищу под ником sormon
за то, что напомнил!
Использование
Здесь будет приведено только использование в Linux (на момент написания статьи последней версией GPG является 2.2.6)
Для начала стоит уточнить, что в большинстве дистрибутивов Linux есть два бинарных файла: gpg
и gpg2
. Насколько я помню, это были две разные версии: 1.4.x и 2.0.x, и для удобного использования я делал alias, чтобы при запуске gpg выполнялся gpg2. Сейчас же в Debian и Arch Linux /bin/gpg2
является символической ссылкой на /bin/gpg
и потребность в таких манипуляциях пропала. Проверить это можно выполнив file /bin/gpg2
.
Введя gpg без аргументов он создаст необходимые ему файлы (если они ещё не созданы) и будет ждать ввода шифруемой информации.
user@PC:~$ gpg
gpg: создан каталог '/home/user/.gnupg'
gpg: создан щит с ключами '/home/user/.gnupg/pubring.kbx'
gpg: Внимание: команда не отдана. Пытаюсь угадать, что имелось в виду ...
gpg: Пишите сообщение ...
При наличии ключа мы можем ввести текст, нажать сочетание клавиш Ctrl + D и получить порцию кракозябр прямо в консоль. Но пока что у нас нет ключа.
Создание ключа
Чтобы создать ключ, нужно запустить GPG с аргументом «—full-generate-key» (можно и с «—gen-key», но в этом случае у нас не будет выбора некоторых важных параметров).
UPD: Если запустить GPG ещё и с аргументом --expert
, то выбор типа ключа будет намного шире. За дополнение спасибо товарищу nikitasius
!
user@PC:~$ gpg --full-generate-key
gpg (GnuPG) 2.2.6; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Выберите тип ключа:
RSA и RSA (по умолчанию)
DSA и Elgamal
DSA (только для подписи)
RSA (только для подписи)
Ваш выбор?
user@PC:~$ gpg --full-generate-key --expert
gpg (GnuPG) 2.2.6; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
RSA and RSA (default)
DSA and Elgamal
DSA (sign only)
RSA (sign only)
DSA (set your own capabilities)
RSA (set your own capabilities)
ECC and ECC
ECC (sign only)
ECC (set your own capabilities)
Existing key
Your selection?
Вы можете выбрать любой вариант, но учтите, что выбрав третий или четвёртый вариант вы не сможете шифровать сообщения и файлы!
...
Ваш выбор? 1
длина ключей RSA может быть от 1024 до 4096.
Какой размер ключа Вам необходим? (2048)
Для RSA ключа размером 2048 бит вполне достаточно, но вы можете выбрать размер до 4096 бит (использовать ключи размера меньше 2048 бит небезопасно).
...
Какой размер ключа Вам необходим? (2048) 2048
Запрошенный размер ключа - 2048 бит
Выберите срок действия ключа.
0 = не ограничен
<n> = срок действия ключа - n дней
<n>w = срок действия ключа - n недель
<n>m = срок действия ключа - n месяцев
<n>y = срок действия ключа - n лет
Срок действия ключа? (0)
Если вы выберете ограниченный срок действия ключа, то по истечению его срока ключ будет признан недействительным. Вы можете продлить срок действия ключа, пока он не истечёт.
GPG спросит, верно ли мы указали срок, и если да, то нужно будет указать имя, адрес электронной почты и примечание (всё это опционально, но нужно указать хотя бы что-то одно).
...
Ключ действителен до Чт 01 января 1970 00:00:00 +00
Все верно? (y/N) y
GnuPG должен составить идентификатор пользователя для идентификации ключа.
Ваше полное имя: Habrahabr User
Адрес электронной почты: habr@habr.com
Примечание: My own key
Вы выбрали следующий идентификатор пользователя:
"Habrahabr User (My own key) <habr@habr.com>"
Сменить (N)Имя, (C)Примечание, (E)Адрес; (O)Принять/(Q)Выход?
Здесь вы можете сделать правки либо продолжить.
Дальше gpg попросит указать пароль (рекомендую освежить память и почитать о правилах выбора стойкого пароля). Если у вас запущен X сервер, то у вас вылезет диалоговое окно, куда нужно ввести пароль. Если же нет, то пароль вводится прямо в консоль.
Если вы не любите окошки
...
Необходимо получить много случайных чисел. Желательно, чтобы Вы
в процессе генерации выполняли какие-то другие действия (печать
на клавиатуре, движения мыши, обращения к дискам); это даст генератору
случайных чисел больше возможностей получить достаточное количество энтропии.
Введите фразу-пароль
для защиты нового ключа
Фраза-пароль:
В терминале вводимый пароль никак не отображается!
Также тут есть полезный совет, который ускорит создание ключа. Следовать ему желательно, но необязательно (и очень аккуратно, чтобы не натыкать лишнего).
...
Фраза-пароль:
Повторите:
Необходимо получить много случайных чисел. Желательно, чтобы Вы
в процессе генерации выполняли какие-то другие действия (печать
на клавиатуре, движения мыши, обращения к дискам); это даст генератору
случайных чисел больше возможностей получить достаточное количество энтропии.
gpg: /home/user/.gnupg/trustdb.gpg: создана таблица доверия
gpg: ключ 5699884482E426AC помечен как абсолютно доверенный
gpg: создан каталог '/home/user/.gnupg/openpgp-revocs.d'
gpg: сертификат отзыва записан в '/home/user/.gnupg/openpgp-revocs.d/2BB6803FCF82316969619C155699884482E426AC.rev'.
открытый и секретный ключи созданы и подписаны.
pub rsa2048 1970-01-01 [SC]
2BB6803FCF82316969619C155699884482E426AC
uid Habrahabr User (My own key) <habr@habr.com>
sub rsa2048 1970-01-01 [E]
На этом этапе ключ генерируется и добавляется в связку ключей
. В связке ключей может находится множество ключей. Также на этом этапе создаётся сертификат отзыва
— файл, с помощью которого созданный ключ можно отозвать (признать недействительным). Рекомендуется хранить его в безопасном месте, т.к. если к нему получат доступ злоумышленники, то они смогут отозвать ваш ключ.
Итак, что же означают все эти странные последние строки?
pub
— Публичный ключ.
sub
— Публичный подключ.
sec
— Секретный ключ.
ssb
— Секретный подключ.
S
— Подпись (Signing).
C
— Подпись ключа (Certification). Об этом пойдёт речь чуть позже.
E
— Шифрование (Encryption).
A
— Авторизация (Authentication). Может использоваться, например, в SSH.
Зачем нужно подписывать сообщения? Для того, чтобы подтвердить, что сообщение написано именно вами и не изменилось в процессе передачи. Если сообщение будет изменено, то при проверке подписи это будет указано.
Конфигурация
Файл конфигурации хранится в файле ~/.gnupg/gpg.conf
Вот, например, пример моего файла конфигурации, который я рекомендую себе поставить:
keyid-format 0xlong
throw-keyids
no-emit-version
no-comments
keyid-format 0xlong
— формат вывода идентификатора ключа. У каждого ключа и подключа есть свой идентификатор. По умолчанию он не выводится, раньше выводилась его короткая версия.
Доступные форматы:
none
— Не выводить (По умолчанию).
short
— Короткая запись.
0xshort
— Короткая запись с префиксом «0x».
long
— Длинная запись.
0xlong
— длинная запись с префиксом «0x».
throw-keyids
— Не включать информацию о ключе в зашифрованное сообщение. Эта опция может быть полезна для анонимизации получателя сообщения.
no-emit-version
— Не вставлять версию GPG в зашифрованное сообщение.
Всё это — опции, которые можно найти в man-странице. В файле конфигурации они записываются без префикса » --
«.
Команды и опции
Я опишу только самое основное.
--armor
-a
— Создаёт ASCII (символьный) вывод. При шифровании GPG по умолчанию создаёт бинарный вывод. При использовании этой опции GPG кодирует информацию кодировкой Radix-64 (Разновидность Base64). Этот текстовой вывод можно, например, отправить в мессенджере или по электронной почте, а также вывести на экран.
--encrypt
-e
— Зашифровать сообщение.
--recipient
-r
— Указать ключ, который будет использоваться для шифрования
. Можно использовать информацию идентификатор пользователя (имя, почта), идентификатор ключа, отпечаток ключа.
--decrypt
-d
— Расшифровать сообщение.
--sign
-s
— Подписать сообщение. Подпись при этом будет распологаться отдельно от самого сообщения.
--clear-sign
--clearsign
— Подписать сообщение. Подпись при этом сохраняется вместе с сообщением.
--verify
— Проверить подпись.
--list-keys
-k
— Вывести список публичных ключей.
--list-secret-keys
-K
— Вывести список приватных ключей.
--export
— экспортировать публичный ключ в файл, который потом можно куда нибудь отправить.
--import
— импортировать публичный ключ.
--edit-key
— Редактировать ключ.
--expert
— «Режим эксперта».
gpg -a -r 0x12345678 -e decrypted.txt > encrypted.gpg
Зашифровать файл decrypted.txt
в файл encrypted.gpg
ключом 0x12345678
. При этом готовый файл будет текстовым, а не бинарным.
gpg -r 0x12345678 -d encrypted.gpg > decrypted.txt
Расшифровать файл encrypted.gpg
ключом 0x12345678
и сохранить его в файл decrypted.txt
.
gpg -u 0x12345678 -s message.txt > sign.asc
Подписать файл message
ключом 0x12345678
и сохранить подпись в файл sign.asc
.
gpg -r 0x12345678 --clearsign message.txt > message.gpg
Подписать файл message.txt
ключом 0x12345678
и записать сообщение с подписью в файл message.gpg
.
gpg --verify message.asc message.txt
Проверить подпись файла message.txt
, которая записана в файле message.asc
.
gpg --import pubkey.gpg
Импортировать публичный ключ из файла pubkey.gpg
.
Редактирование ключа, подпись чужих ключей и отправка ключа на сервер ключей
Ключ редактируется командой gpg --edit-key <KeyID>
.
После ввода этой команды вы увидите это:
user@PC:~$ gpg --edit-key CCA230DA07929EB7
gpg (GnuPG) 2.2.6; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Секретный ключ доступен.
sec rsa2048/CCA230DA07929EB7
создан: 2018-05-08 годен до: никогда назначение: SC
доверие: абсолютное достоверность: абсолютное
ssb rsa2048/7859E2A888E31276
создан: 2018-05-08 годен до: никогда назначение: E
[ абсолютно ] . Habrahabr User (My own key) <habr@habr.com>
gpg>
Доступные команды вы можете узнать, введя help
.
Здесь мы можем добавить различные подключи, добавить идентификаторы пользователя, а также подписать чужие публичные ключи.
Для чего нужно подписывать ключи? Так вы можете подтвердить то, что владелец подписываемого ключа является тем, за кого он себя выдаёт. Таким образом вы создаёте так называемую «Сеть Доверия». Пример: Алиса подписала публичный ключ Боба, а Боб подписал публичный ключ Чарли. Если Алиса получит публичный ключ Чарли, она сможет ему доверять, потому что ключ подписан тем, кому Алиса доверяет, т.е. Бобом. Для того, чтобы получить подписи для своего ключа, люди даже устраивают специальные встречи, где они обмениваются своими публичными ключами и подписывают их.
Теперь о серверах ключей. Сервер ключей
— это специальный сервер, хранящий публичные ключи. Сервера ключей используются для распространения публичных ключей.
Внимание! Ключи, отправленные на сервер ключей, невозможно удалить! Их можно только отозвать, импортировав сертификат отзыва на сервер, при этом ключ всё равно остаётся на сервере.
Отправить публичный ключ на сервер:
gpg --keyserver <URL> --send-keys <KeyID>
Получить публичный ключ с идентификатором ключа с сервера :
gpg --keyserver <URL> --recv-keys <KeyID>
Получить обновления ключей с сервера:
gpg --keyserver <URL> --refresh-keys
Найти ключ на сервере:
gpg --keyserver <URL> --search-keys <UID или KeyID>
Для удобства можно прописать адрес сервера ключей в gpg.conf
, чтобы не прописывать его в командах:
keyserver <URL>
Где вы можете столкнуться с использованием GPG
Git
Вы можете использовать GPG для подписи ваших коммитов. Так вы подтверждаете, что коммит сделали именно вы. В GitHub можно импортировать свой публичный ключ и коммиты, подписанные вашим ключом, получат «галочку».
UPD: О конфигурации Git для использования GPG вы можете прочитать в документации по Git
.
Вот пример файла конфигурации Git`а от товарища nikitasius
:
[commit]
gpgsign = true
[user]
signingkey = <KeyID>
[gpg]
program = /bin/gpg
Загрузка дистрибутивов и прочих файлов
Большинство установочных образов дистрибутивов распространяются подписанными разработчиками. Если вы загрузите модифицированный образ, то при проверке подписи вы сразу заметите, что образ не оригинальный. Примером служит популярный дистрибутив Tails.
Пакетные менеджеры
Все пакеты подписываются разработчиками для защиты от изменений. При установке пакетов эти подписи проверяются. Делается это всё автоматически без вмешательства пользователя.
Ссылки
Сайт GPG
Статья о GPG в Википедии
Сайт, посвящённый ИБ и GPG
Сервера ключей:
pgp.mit.edu
keyserver.pgp.com