На главную

Удалённый обмен ключами

Любой сценарий обмена информации, где задействованы компьютеры, начинается с обмена ключами. Всегда и везде компьютерная информация при обмене шифруется, да и при хранении, шифруется. Как мы понимаем, модель угроз (и доверия) может быть разной. Так, если мы хотим защититься против обычного просмотра нашей переписки с целью выдачи нам рекламы, достаточно самых простых способов согласования ключей. Если же от шифрования зависят жизни человека, то всё может быть куда сложнее. Давайте начнём с чего попроще. Будем считать, что защищаемся просто от обычного корпоративного прослушивания, а не от ФСБ или АНБ. Также будем считать, что мы хотим просто общаться с друзьями и товарищами, не заморачиваясь передачей ключей шифрования лично. Пока попробуем поговорить об обмене асимметричных ключей.
Прежде всего, ключи шифрования могут подменяться сразу при обмене. Если работаем с ключами, которые согласуются не лично, а через интернет, то такие ключи могут быть автоматически подменены. Однако, если мы просто хотим зашифровать незначительные тексты в электронной почте, то вряд ли за нами будут следить спец. службы. Но, например, чисто теоретически, за вами может следить ваш интернет-провайдер. В том числе, если вы шифруете на рабочем месте - ваш работодатель. Давайте посмотрим, что нужно уметь злоумышленнику для того, чтобы подменить ключи шифрования K1. Ему нужно показать, что вы отправили ключ шифрования K1. Подменить ключ K1 на другой L1, а оригинальный K1 сохранить. Затем, когда ваш собеседник зашифрует ключом L1 информацию, её должны перехватить, перешифровать ключом K1, и отправить вам. Таким образом, злоумышленник: 1. Имеет контроль над каналом связи или приложением, через которое вы отправляли ключ K1 2. Имеет контроль над каналом связи или приложением, через которое вы получали текст, который должен быть зашифрован ключом K1 3. Распознать пересылку ключа K1 в автоматическом виде или достаточно быстро (может быть, с возможностью задержать отправление) 4. В автоматическом виде или достаточно быстро, подменить ключ K1 на ключ L1. 5. Аналогично, перешифровать сообщение, зашифрованное ключом L1 на K1 Как видно, злоумышленнику нужно иметь контроль над каналами связи, через которые вы посылаете ключ и получаете сообщения. Первый вариант защиты состоит в том, чтобы разделить эти каналы связи. То есть ключ вы посылаете, например, из дома, а сообщения принимаете на работе. Или наоборот. Таким образом, если домашний канал связи никак не соотносится с рабочим, то контроля за обоими каналами связи у злоумышленника нет. Опять, же, у ФСБ есть контроль над всеми каналами связи, но мы его сейчас не рассматриваем. Давайте попробуем привести пример такой защиты. С работы я отправляю публичный ключ шифрования. На работе используют провайдера "Паечка". Отправляю я через почтовое отправление. На работе используют Google почту для организаций. Дома у меня провайдер "Ёжик". Использую почту Яндекс. Таким образом, я использую два разных канала связи: Яндекс и "Ёжик" - дома. Google и "Паечка" - на работе. Всё нормально? Я совершил две ошибки. 1. Если Паечка и Ёжик заключили соглашение о совместном использовании каналов связи, то, посылая ключ через Ёжик, вы посылаете его через оборудование Паечки. Иногда проверить это достаточно просто. Например, зайти на какой-нибудь сайт типа 2ip.ru и посмотреть, какого провайдера на ваш IP пишет этот сайт. Проблема в том, что это не гарантирует от того, что пересылка не произойдёт через какого-то одного провайдера. Например, через магистрального провайдера. То есть у вас на маршруте пакетов, грубо говоря, могут быть одни и те же сервера или сервера, принадлежащие одному и тому же провайдеру. 2. Я забыл про то, что мой товарищ принимает от меня пакеты, возможно, через один и тот же канал связи. То есть если он принял ключ дома и отправил шифрованное сообщение также из дома, то его домашний оператор имел доступ и к ключу, и к сообщению. Разумеется, мы можем оба договориться и сделать всё верно. Пути сообщений проверить через команду tracert (под Windows; под Linux - traceroute), а потом по IP-адресам посмотреть, кому они принадлежат. Хотя... остался ведь путь от одного почтового ящика до другого. В данном случае, мы можем пересылать друг другу сообщения внутри одной и той же почтовой системы. Хотя это не гарантирует, что пакеты не выйдут за пределы этой системы. То есть при пересылке по электронной почте мы не можем точно установить путь от одного почтового провайдера к другому. То же касается и любой другой пересылки, если мы не пользуемся одним и тем же сервером. Получается довольно сложно, муторно и не очень ненадёжно. Такой путь, наверное, не самый приятный. Внимательный товарищ, читая книгу с карандашом и пососав карандаш, спросит: "а как же TLS?". Ведь у нас же всё шифровано? Чем шифровано? Мы ведь и обсуждаем то, как гарантированно передать ключи шифрования. Почему мы решили, что шифрование TLS надёжно передало нам хотя бы открытые ключи? Может быть, мы скачали из интернета не наш браузер, а наш браузер с подменой открытых ключей шифрования? Если вы считаете, что это невозможно, не тратьте напрасно время, читая курс дальше. Кроме этого, мы ведь не соединяемся по TLS напрямую прямо с нашим собеседником. Мы соединяемся с сервером Мы помним, также, что в том же FireFox на момент 2015-ого года было зарегистрировано более 150-ти сертификатов, принадлежащих разным центрам шифрования. Например, из Турции, Японии и т.д. Взлом хоть одного из них повлечёт за собой общую компрометацию системы. Хищения приватных ключей корневых сертификатов были неоднократно. Таким образом, TLS доверять нельзя. Это лишь начальное закрытие, обфусцирующее канал связи. TLS - гражданское шифрование почти самого низкого уровня доверия. Вспомним также, что довольно неоднозначная технология HPKP была убрана из браузера Google Chrome, хотя довольно серьёзно повышала уровень безопасности. Впрочем, Mozilla наоборот, примерно в то же самое время добавила на некоторые поддомены своего сайта HPKP, оказав поддержку этой технологии на сайте и в браузере FireFox. Что не значит, что этот браузер безопасен, а Mozilla ни с кем не сотрудничает. Короче говоря, мы стремимся доверять как можно меньшему количеству лиц и технологий. А TLS - не самая заслуживающая доверия. Массовая, удобная, но недоверенная.
Как же быть? Как более-менее гарантированно передать открытый ключ шифрования? Разумеется, как предполагает это делать концепция PGP - лично. Но лично мы и передадим и ключ симметричного шифрования и актуальность асимметричной криптографии для нас будет потеряна вообще. Можно ли как-то ещё? С таким же уровнем доверия, как при личной встрече, решить проблему удалённо не получится. Недаром Сноуден передавал ключ шифрования лично через посредника. Он действовал наверняка, зная, что любой канал связи прослушивается АНБ (NSA) США и может быть не только прослушан, но и подменён. Прежде всего, проблема в том, общаемся ли мы с этим человеком или нет? Допустим, мы считаем, что общаемся именно с ним. Но как это проверить? Даже если мы позвоним по телефону, сейчас существуют синтезаторы голоса, похожего на заданный образец голоса. То есть, чисто теоретически, таким синтезатором нас можно обмануть. Однако, сейчас мы боремся не против ФСБ РФ или АНБ США. Мы боремся против частной - корпоративной - прослушки. Против социальных сетей, рекламных фирм и т.п. Задержка сообщений при их доставке и, тем более, подделка голоса по телефону, вряд ли ими будет использована. Так как такие корпорации всё делают тихо и совершенно не хотят огромного скандала. Хотя, с другой стороны, а что им за это будет? Похулиганили с телефонами... ну, максимум, уголовка какому-нибудь стрелочнику-администратору системы, который, как окажется, действовал сам. А главы компаний и не знали. Ах, ох, какой ужас. Но, всё же, давайте обопрёмся на то, что сообщения не задерживаются специально и не подменяются просто так. Представим себе, что подмене подвергаются только ключи шифрования. А всё, что можно и так прослушать, никогда не подменяется.
В таком пограничном случае, решение есть. Зашифруйте открытый ключ шифрования никому не известным паролем. Он известен только одному человеку - вам. Мы предполагаем доверие вашему компьютеру. Допустим, открытый ключ - это K1. Мы зашифровали его паролем P1. Обозначим полученный шифротекст K1P1. Теперь мы можем K1P1 направить нашему собеседнику. Он, по другому каналу связи, скажем, по телефону, диктует нам хеш полученного K1P1. Мы убеждаемся в его правильности. После чего, по этому же каналу, даём ему пароль для расшифровки. Таким образом, пока мы передаём информацию, никто, кроме нас, не может подменить сообщение. Потому что даже его получатель не знает, как его расшифровать. Что бы подменить сообщение, его должны задержать. Однако, если мы считаем, что задерживать его не будут, то мы можем думать, что сообщение дошло в целостности. Проверка хеша по другому каналу связи дополнительно подтверждает, что дошло именно то сообщение, о котором мы говорим. В принципе, она уже не так важна. В этот момент, мы можем считать, что дошёл именно тот открытый ключ, который нужен. Конечно, если кто-то слушает наш телефон, он поймёт, что мы что-то пересылали и, вероятнее всего, тоже сможет расшифровать перехваченный архив. Но для этого ему нужно перехватывать все каналы связи. А пересылали-то мы всё равно открытый ключ. То есть шифрованием мы его защищали от подмены, а не от расшифровки. Напомню, что в данном случае, мы согласовывали асимметричные ключи для проверки подлинности сообщений и, возможно, для шифрования сообщений.
Можно чуть усилить схему, но не сильно. Прежде всего, усилить схему можно стеганографией. Передавая зашифрованный открытый ключ, вы можете сначала зашифровать его, а потом, дополнительно, застеганографировать, например, в изображение (см. программу в списке сервисов, ссылка на главной странице). И уже это изображение, не указывая явно, что это ключ, передать собеседнику. Изображение должно быть передано в оригинале, без перекодирования, иначе стеганографическая информация будет потеряна. Теперь прослушка может даже не понять, что передавался ключ. Далее, собеседник, получивший ваш ключ, по телефону узнаёт от вас ссылку (точнее, её часть) на одноразовую записку (см. в списке сервисов), где хранятся пароли от стеганографии. Записка должна быть именно одноразовой. То есть уничтожаться при прочтении, а не по времени. Это позволит убедится, что никто другой её не читал. Опять же, без сговора с сервисом одноразовых записок и без его подделки. Мы ограниченно доверяем этому сервису и тому, что работаем именно с ним. Если телефон использовать нельзя, можно использовать другой канал связи. Желательно, со своим, отличным от других каналов, шифрованием. Наконец, после этого, вы можете сообщить пароль от ключа каким-либо другим каналом, или даже тем же самым. Например, вы можете сообщить по bitmessenger ссылку на одноразовую заметку privnote, а потом через TorChat сообщить пароль от расстеганографированного ключа.
Помните, что отсылка с определённым ключом шифрования может оказаться доказательством, подтверждающим, что именно вы ведёте переписку с кем-либо. Асимметричные ключи не доказывают, что вы переписываетесь именно с этим человеком: ведь вы не видели его лично. Но, часто, нам это не очень надо, так как информация, передаваемая таким способом, не самая важная. В то же время, такой способ позволяет без особых напрягов довольно надёжно скрыть передаваемый ключ. Однако, повторюсь, если жизнь человека зависит от надёжности шифрования - асимметричная криптография не ваш друг. Она может быть использована только как дополнительный инструмент защиты. Хотя тот же Сноуден пользовался ей, фактически, как основным способом. Но, конечно, согласовывая ключи лично через посредника. Если у вас есть возможность согласовать ключи лично, наряду с асимметричными ключами, обязательно согласуйте симметричные. Тем более, что квантовые компьютеры привносят в асимметричную криптографию серьёзную неразбериху. Пока они ещё не стали достаточно мощными, можно использовать даже RSA. Кстати, RSA предпочтительнее, чем эллиптические кривые, потому что занимают больше битов, а значит, требуют более мощного квантового компьютера.
Давайте попробуем рассмотреть сценарий передачи с конкретными программами. Я буду использовать Windows, но пользователи Linux, я думаю, тоже разберутся со своими программами. Для шифрования я буду использовать диск в оперативной памяти. Я создам новый ключ асимметричного шифрования на нём, потом зашифрую этот ключ и сохраню на несекретном носителе информации в качестве резервной копии. Потом зашифрую этот ключ уже для передачи данных. Застеганографирую его, создам заметку, и, наконец, передам.
Создадим диск в оперативной памяти Диск в оперативной памяти я создаю для того, чтобы на жёстком диске компьютера не осталось следов нерасшифрованной информации. Используя ImDisk с соответствующей оснасткой, я выбираю в меню File "Mount new virtual disk". Ставлю удобный мне "Drive letter", то бишь букву диска. Например, "W:". Image file оставляю незаполненным. Создаю диск небольшого размера. Примерно половина от него будет занята служебными данными, поэтому я создам 2 Мб из расчёта на то, что реально мне понадобится 1 Мб. Выбираю "Create virtual disk in virtual memory", то есть создаю диск в памяти. Мне неизвестно, защищает ли ImDisk от выгрузки в файл подкачки данные из виртуальной памяти. Я не выбираю "Create virtual disk in physical memory", так как диск всё равно не будет выгружен в файл подкачки, так как у меня отключён файл подкачки. Если у вас файл подкачки (он же swap-файл) включён, возможно, стоит выбрать "Create virtual disk in physical memory". Если вы делаете это под виртуальной машиной, то файл подкачки должен быть отключён и на хосте, и на гостевой машине. Так же, я отмечаю диск как "Removable media". Обычно это позволяет уменьшить кеш операционной системы на запись. Хотя, в целом, это не важно. Нажимаю "OK". И, о чудо!, диск создан. Windows предлагает его отформатировать. Ну что же, FAT подойдёт :) . В качестве метки тома, чтобы не перепутать, можно поставить "Временный".
Создание пары RSA-ключей. Допустим, у меня ещё нет асимметричного ключа шифрования. Так что я создам его. Для Windows, как вариант, я могу скачать уже бинарную версию OpenSSL с http://slproweb.com/products/Win32OpenSSL.html (достаточно Light-версии). Либо скомпилировать из исходников https://www.openssl.org . Под Linux OpenSSL стоит по умолчанию. Вы можете использовать и GnuPG, но я буду использовать OpenSSL. Допустим, у нас уже есть бинарники. Открываем cmd.exe (под Windows) или терминал под Linux (ctrl+alt+T под Ubuntu). Проверяем, что OpenSSL у нас находится в Path. Для этого просто вводим команду openssl version После команды не забываем нажать Enter. Надеюсь, вы знаете, как всё это делать. Если выдалась информация о версии OpenSSL, то всё нормально. Что-нибудь похожее на это "OpenSSL 1.1.1d 10 Sep 2019". Если выводится сообщение об ошибке, значит в Path её нет и надо искать директорию (папку), где лежат исходники. Перейти на другой диск под Windows можно просто набрав имя диска и двоеточие и нажав Enter (каждая команда заканчивается нажатием на Enter). Например, "E:" и нажав Enter. Перейти в корневую папку можно выполнив команду cd / Найдите папку в проводнике операционной системы и введите в консоли путь. Например, если OpenSSl установлена у вас в папке C:\Криптография и стеганография\openssl, а exe-файл лежит в папке bin, то набор команд будет примерно таким. C: cd "Криптография и стеганография" cd openssl cd bin Если у вас возникают с этим трудности, посмотрите руководство по командной строке вашей операционной системы. Снова введём openssl version Если теперь ошибки нет, значит всё в порядке (если выдаётся версия OpenSSL). Для генерации ключа шифрования сначала сгенерируем дополнительный файл со случайными данными. Используем для этого VeraCrypt (я использую свою программу, но здесь рассмотрим именно VeraCrypt). В VeraCrypt пройдём в меню Сервис -> Генератор ключевых файлов. Поставим размер файла на 2048 (это 16384 бита) или более. Постарайтесь перемещать мышкой дольше, чем рекомендует VeraCrypt. Введём имя файла rnd (или любое другое вам удобное). Убедившись, что полоса энтропии зелёная, нажмём кнопку "Создать и сохранить файл". Выберем местоположение на созданном нами ранее диске "W:" , то есть файл со случайными данными будет иметь полное имя W:\rnd . Теперь нам нужно сгенерировать ключи RSA. Генерация пары ключей RSA, размера 16384 битов может занимать длительное время (причём время это всегда разное). Но, вообще говоря, речь идёт о единицах минут (у меня в этот раз ключ сгенерировался за 6 минут.). Размер ключа 16384 бита максимальный. Определён в файле rsa.h заголовочных файлов OpenSSL уже много лет константой OPENSSL_RSA_MAX_MODULUS_BITS, равной 16384. Введите команду, аналогичную данной: openssl genrsa -rand W:\rnd -out W:\key.priv 16384 Здесь мы вызываем openssl с командой genrsa. Эта команда говорит, что нужно сгенерировать пару ключей RSA. Опция -rand говорит, что мы берём дополнительные случайные данные из файла. Это файл W:\rnd (введите то название, которое у вас). Опция -out говорит, как будет называться файл со сгенерированной парой ключей. У меня это W:\key.priv . Наконец, 16384 говорит о том, какой длинны будет сгенерирован ключ RSA. Обратите внимание, я преднамеренно не стал зашифровывать этот файл. Сейчас наш ключ абсолютно беззащитен. Именно поэтому я использую диск в оперативной памяти для его временного хранения. Его просто нельзя хранить где-либо ещё. Его можно зашифровать любой программой. Например, OpenSSL, 7-zip (см. ссылки на сервисы на главной странице). Если вы хотите зашифровать ключевой файл сразу при создании, вы можете ввести команду openssl genrsa -rand W:\rnd -out W:\key.priv -aes-256-cbc 16384 После генерации openssl предложит вам ввести пароль к данному файлу. При работе с этим файлом всегда надо будет вводить пароль. key.priv - это файл, который никогда никому не надо передавать. Он содержит приватный (секретный) ключ RSA. Нам нужно извлечь публичный ключ RSA в отдельный файл. В команду ниже подставьте свои пути файлов. openssl rsa -in W:\key.priv -out W:\key.pub -pubout -check Теперь в файле W:\key.pub будет наш публичный ключ. Его можно публиковать. Обязательно проверьте, что указали ключ "-pubout" - это говорит о том, что мы получаем на выходе именно публичный ключ. Проверьте, файл W:\key.priv лично у меня примерно 13 кб, а W:\key.pub - примерно 3 кб. Так и должно быть. Файл с публичным ключом должен быть гораздо короче, чем файл с приватным ключом. Всегда проверяйте, чтобы случайно не послать кому-то приватный ключ. Итак, мы сгенерировали два файла: W:\key.priv и W:\key.pub . В key.priv содержится приватный ключ. Мы его зашифровали и храним в таком виде. Никому не даём. key.pub можем публиковать где хотим вообще. Это публичный ключ, который мы будем далее передавать всем остальным.
Согласование ключей. Теперь мы согласовываем с Колей ключи шифрования. В самой простой форме мы пошлём файл key.pub Коле. Однако, его могут подменить. Так что давайте зашифруем любой программой файл key.pub . Например, застеганографируем с шифрованием в OpenPuff или любой другой. И передадим его Коле. Пусть это будет файл key.pub.crypted . Разумеется, в реальной жизни его надо называть как-нибудь типа tree.jpg (стеганографируется он в картинки обычно). После этого, Коля звонит нам и подтверждает хеш сообщения. Рассчитать хеш можно командой openssl dgst -sha3-512 W:\key.pub.crypted Как вариант, он нам просто шлёт хеш, но по другому каналу связи, нежели вы посылали ему зашифрованный файл. Например, посылаем мы ему через vk.com , он шлёт назад через bitmessenger. Мы сравниваем хеши. Если всё нормально, то мы говорим Коле пароль от файла. В принципе, мы можем передать пароль по любому каналу. Как вариант, особенно, если мы сгенерировали файл специально для Коли, мы передаём пароль от файла не сразу Коле. Мы постим его в одноразовой заметке, а Коле передаём url этой заметки. Если кто-то другой захочет прочитать заметку, он её удалит (она же одноразовая), поэтому это дополнительная защита от того, чтобы записку никто не подменил. Таким образом, мы дополнительно убеждаемся, что именно Коля прочитал записку. Кроме этого, если мы доверяем сервису одноразовых записок (что он не сохраняет записок), то мы таким образом ещё и дополнительно обеспечили конфиденциальность пароля. Последнее имеет смысл только если мы специально для Коли генерировали новый ключ RSA. Ещё раз повторюсь: гораздо лучше встретиться лично. Но на безрыбье и рак рыба. Теперь Коля начинает работать с нашим публичным ключом. Он расшифровал key.pub.crypted и получил наш публичный ключ RSA key.pub . Коля создаёт ключ для симметричного шифрования sym.key . Это можно сделать той же VeraCrypt так, как описывалось выше, или другим ПО. Для начала зашифруем sym.key публичным ключом (подставьте имена файлов) openssl rsautl -inkey W:\key.pub -pubin -encrypt -oaep -in W:\sym.key -out W:\sym.key.rsa Теперь sym.key был зашифрован в файл sym.key.rsa . Далее, Коля передаёт этот ключ нам. Он опять может зашифровать этот ключ дополнительно, другой программой, а пароль к нему передать через сервис одноразовых записок. Это повысит секретность. Мы приняли файл sym.key.rsa . Если надо, расшифровали его, узнав пароль. Теперь нам надо расшифровать его асимметричным алгоритмом RSA. Команда будет аналогично данной ниже openssl rsautl -inkey W:\key.priv -decrypt -oaep -in W:\sym.key.rsa -out W:\sym.key Теперь у нас тоже есть файл sym.key . Этот файл также нельзя хранить в расшифрованном виде иначе, как на диске в памяти. Это беззащитный ключевой файл. Теперь мы можем использовать этот ключевой файл в любой программе, которая позволяет симметрично шифровать ключевыми файлами.
Симметричное шифрование. Для примера, посмотрим, чем можно зашифровать в openssl. Выполним команду openssl enc -ciphers Мы увидим, какие симметричные шифры можно использовать в openssl. Однако, файл sym.key мы не сможем использовать в бинарном виде с openssl. Так как openssl не принимает ключи, только пароли. Давайте преобразуем файл в base64 и используем его так в качестве пароля. openssl base64 -A -in W:\sym.key -out W:\pwd.txt Обратите внимание на опцию -A. Она позволяет получить base64 в файле в одну строку (пароль должен быть именно в первой строке). Теперь будем шифровать файл data.txt . openssl enc -e -aes-256-cbc -md sha3-512 -salt -pbkdf2 -iter +1000000 -pass file:W:\pwd.txt -in W:\data.txt -out W:\data.txt.crypted Файл data.txt.crypted надо отправить Коле. Коля его расшифрует командой openssl enc -d -aes-256-cbc -md sha3-512 -salt -pbkdf2 -iter +1000000 -pass file:W:\pwd.txt -in W:\data.txt.crypted -out W:\data.txt Обратите внимание, параметр -iter +1000000 должен быть одинаков у обоих сторон. Чем больше этот параметр, тем дольше из парольной фразы идёт генерация уникального ключа шифрования для этой операции шифрования. Такие мучения с openssl не обязательны. Можно шифровать любыми другими программами. Главное, для чего нам нужен был openssl, это согласовать симметричный ключ sym.key .
Подтверждение установления канала связи В идеале, Рома и Коля должны проверить, что они действительно получили верные ключи. Для этого Рома генерирует случайное сообщение. Например, "0Hz68JjU80QmxDITISjvQZmZ". Оно генерируется только после того, как произошёл обмен ключами. Далее Коля вычисляет хеш этого сообщения и шлёт его Роме. Все посылки выполняются в зашифрованном виде, с использованием согласованного ключа шифрования. Коля действует аналогично. Рома и Коля проверяют полученные хеши и сообщают друг другу об установлении канала связи. После этого канал связи можно считать установленным и каналом можно пользоваться для шифрования важной информации. Подтверждение установления канала связи необходимо для того, чтобы точно установить работоспособность ключа и его наличие у обоих сторон в неповреждённом виде. В принципе, подтверждение можно осуществлять и без вычисления хешей: просто написать, что ключи получены. Но хеши позволяют точно проверить, что Рома смог зашифровать, Коля именно это смог расшифровать, затем смог зашифровать нечто другое и Рома именно это смог расшифровать. То есть провести проверку полного цикла связи.
Контрольный список: удалённый обмен асимметричными ключами Обмен симметричными ключами