Как посчитать имитовставку mac функциями openssl
Перейти к содержимому

Как посчитать имитовставку mac функциями openssl

  • автор:

Как посчитать имитовставку mac функциями openssl

Продолжая традицию, начатую в статьях 1 и 2 нашего блога, предлагаем обсудить еще одну из атак на протокол TLS. В сегодняшней статье будет рассмотрено, как предпринятые в TLS 1.1 и TLS 1.2 контрмеры, направленные на устранение уязвимости протокола к атакам, основанным на методах Барда-Дэя и Воденея, сами привели к возникновению новых уязвимостей и к появлению новых типов атак.

Для ликвидации уязвимости к атакам, аналогичным атаке Воденея, был принят ряд контрмер, связанных с порядком вычисления имитовставки при некорректном заполнении. В пункте 6.2.3.2 RFC 5246 (описание протокола TLS версии 1.2) присутствует следующая рекомендация: указано, что лучшим методом защиты от временных атак, аналогичных атаке Воденея, является вычисление значения имитовставки даже в случае некорректного заполнения, например, вычисление значения имитовставки по всему полученному после расшифрования фрагменту в предположении отсутствия заполнения.

«For instance, if the pad appears to be incorrect, the implementation might assume a zero-length pad and then compute the MAC. This leaves a small timing channel, since MAC performance depends to some extent on the size of the data fragment, but it is not believed to be large enough to be exploitable, due to the large block size of existing MACs and the small size of the timing signal.»

Таким образом, указано, что предлагаемые меры оставляют временной канал утечки информации, связанный с наличием разницы во времени вычисления имитовставки в случае сообщения с корректным заполнением (время вычисления самого сообщения) и модифицированного сообщения с некорректным заполнением (время вычисления сообщения и соответствующих заполнению байтов). Также сделан вывод, что канал невозможно использовать по причине большого размера блока современных алгоритмов выработки имитовставки. Буквально сказано так: «предполагается, что временной канал недостаточно большой для его использования».

Не странно ли видеть слова «предполагается, что это безопасно» в спецификации криптографического протокола? Так вот, это предположение оказывается неверным.

Атака Аль-Фардана и Патерсона или Число 13 приносит удачу

При наличии низкоинформативного побочного канала возможны два пути его эксплуатации. Первый путь заключается в нахождении относительно реалистичных условий, при которых возможно стабильное долговременное использование данного канала, обеспечивающее достаточный для анализа объём получаемых данных.

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

Успехов на первом пути добились Аль-Фардан (AlFardan) и Патерсон (Paterson) из Лондонского Университета (City University London). Метод Аль-Фардана–Патерсона предполагает модель нарушителя, в которой нарушитель имеет возможность наблюдать и подменять сообщения в канале в точке, близкой к атакуемому клиенту или серверу. Неформально определенное требование «близости» происходит из необходимости работы с крайне слабым побочным каналом по времени.

Опишем построение данного канала утечки и использование этого канала для дешифрования блока Сi (здесь и далее используются обозначения из этой статьи) передаваемого по каналу связи шифртекста С = (С123|. |Cm) = Ek(M1|M2|M3|. |Mm). Будем считать, что для шифрования используется AES (важен не сам алгоритм шифрования, а его длина блока) с длиной блока равной 128 бит, а для выработки кода аутентификации используется HMAC-SHA-1 с длиной блока 160 бит.

Для некоторого случайно выбранного значения Ω сформируем шифртекст C att ( Ω ) = (HDR|IV|C1|C2|Ci‑1⊕ Ω |Ci) , где HDR – заголовок, C0 – произвольный блок. После расшифрования на стороне получателя последний блок P4 будет равен Dk(Ci) ⊕ Ci‑1 ⊕ Ω = Mi. Далее возможны следующие три случая: блок Mi ⊕ Ω в конце содержит корректное заполнение длины 1, длины 2 (или более, с вероятностью в 256 раз меньшей), либо некорректное заполнение.

С учётом указанной выше рекомендации RFC 5246, в случае некорректного заполнения код аутентификации сообщения вычисляется по всему тексту, т.е. до конца блока Mi. По свойствам протокола TLS, в этом случае он вычисляется на 57 или более байт, если заголовок имеет длину 13 байтов (отсюда название атаки «Lucky Thirteen»), а в случае корректного заполнения длины 1 – на 56 байт. В случае же, когда присутствует корректное заполнение длины 2 и более, происходит расчёт кода аутентификации сообщения на 55 или менее байт.

С учетом структуры HMAC-SHA-1, в случае длины аутентифицируемых данных 55 или менее требуется не более 4 вычислений функции сжатия SHA-1, тогда как при длине 56 или более требуется 5 или более вычислений. После этих вычислений происходит возврат ошибки (вероятность появления коллизий при проверке HMAC-SHA-1 пренебрежимо мала), которую наблюдает нарушитель.

Измерение времени до возврата ошибки позволяет использовать побочный канал по времени, связанный с количеством вычислений функции сжатия. В случае быстрого возврата ошибки (4 вычисления функции сжатия) нарушителю известно, что в последних 2 байтах (или более, но вероятность этого меньше в 256 раз) Mi ⊕ Ω содержится корректное заполнение. Зная структуру заполнения и значение Ω, нарушитель однозначно определяет последние два байта Mi. Зная последние два байта Mi, далее возможно тем же способом, модифицируя Ω , восстановить третий с конца байт Mi, и так далее.

Звучит интересно, а что на практике?

Допустим что сервер, клиент и атакующий находятся в одной сети VLAN с пропускной способностью 100 Mbps. Атакующий начинает перехватывать пакеты от клиента к серверу, модифицировать их и отправлять на сервер и собирает статистику по времени получения сообщений TLS alert от сервера. Для повышения скорости атаки сразу после получения ответа от сервера атакующий отсылает клиенту и серверу RST пакет, который приводит к мгновенному закрытию соединения. Для подбора каждого байта в худшем случае нужно L*256 попыток, где L – это количество попыток с одинаковым Ω . Несколько попыток с одинаковым Ω нужно для уменьшения вероятности неправильной трактовки результата. Эксперименты показали что вероятность правильного подбора байта при росте L от 1 до 128 изменяется от 0,756 до 1. Уже при L=8 вероятность удачи равна 0.914. Это говорит о том, что даже при одной попытке на каждое Ω мы имеем достаточно большую вероятность правильно отличить ошибки заполнения от ошибки имитозащиты. На момент публикации статьи практически все известные реализации TLS (OpenSSL, GnuTLS, NSS, Java BC, PolarSSL, yaSSL) были уязвимы к данному варианту временной атаки.

Наша атака или А если нет разницы, зачем заполнять меньше?

Годом ранее на конференции РусКрипто’2012 специалистами ООО «КРИПТО-ПРО» была представлена другая временная атака, направленная на расширение побочного канала.

Заметим, что в пункте 6.2.3.2 RFC 5246 указано, что заполнение может иметь любую длину, не превосходящую 255 байтов, обеспечивающую должное выравнивание. Таким образом, при размере блока алгоритма выработки имитовставки в 16 байтов сообщение длиной, например, 16 байтов, дополненное 240 байтами вида 0xf0, будет считаться дополненным корректно, и при проверке корректности сообщения будет вычисляться имитовставка на 1 блок. В случае же контролируемой модификации конечных блоков данного открытого текста (производимой аналогично методу Воденея) заполнение будет приниматься как некорректное, и имитовставка будет вычисляться на 16 блоков, обеспечивая существенную разницу во времени вычисления, создающую потенциальный канал утечки информации. По сравнению с атакой « Lucky Thirteen » э то позволяет ослабить требование по « близости» нарушителя к атакуемому клиенту или серверу. Наша атака работает в модели нарушителя, аналогичной BEAST , т.е. помимо навязывания шифртекста нарушитель имеет возможность навязывать открытый текст для зашифрования.

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

Благодаря данному временному каналу восстанавливается последний байт блока, предшествующего добавляемой части. После определения данного байта, аналогичным образом восстанавливается предшествующий ему, и так далее.

Описанная в нашей статье атака не может быть осуществлена напрямую из браузера сценарием JavaScript, т.к. этот уровень не управляет дополнением открытого текста для выравнивания границ блоков – это происходит на уровне реализации протокола TLS. Тем не менее, несложно модифицировать данную атаку таким образом, что она будет осуществима с помощью сценария JavaScript. Для этого понадобится, чтобы сценарий нарушителя дополнял отправляемое в канал сообщение в конце до границы блока аналогичным образом, но при этом отбрасывал последний байт. Тогда реализация TLS добавит заполнение в 1 байт вида 0x00, и у атакующего остаётся возможность подбирать открытый текст побайтово с конца в условиях существенной разницы по времени вычисления имитовставки при корректном и некорректном заполнении.

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

Судя по всему, тема атак на протокол TLS неисчерпаема, а значит, нам будет о чём писать в нашем блоге. Не отключайтесь!

Беляев Анатолий
Смирнов Павел
Смышляев Станислав

SSH с высоты птичьего полёта, или разгребаем кучи ключей

Решил я недавно разобраться в подробностях работы SSH. Использовал его для удалённого запуска команд давно, но, будучи не слишком опытным в системном администрировании, очень размыто представлял, зачем админы просят им отправить какой-то ключ, что с этим ключом происходит при подключении, зачем при запуске ssh периодически орёт на меня какими-то предупреждениями, и прочие прелести. К своему удивлению, не смог найти ресурсов с описанием протокола, после которых у меня не осталось бы только больше вопросов. Поэтому, после прочтения спецификаций и разборок с OpenSSH, хочу разложить всё по полочкам здесь.

Статья рассчитана на тех, кто поверхностно знаком с SSH, возможно, использовали на практике, но не осознали его сакральных смыслов и глубоких тайн. Попытаюсь описать основные аспекты безопасности протокола: какие ключи и алгоритмы используются, в какой момент и зачем. Статья призвана дать базу в работе с самим протоколом SSH, зная которую можно разбираться в его более продвинутых возможностях. Также будут замечания, как некоторые компоненты протокола претворяются в жизнь в OpenSSH на линуксе (конкретной программе, наверное, самой популярной, реализующей протокол SSH).

Что нужно знать

Единственное требование: знать об (а)симметричном шифровании и цифровой подписи. Что такое криптографический ключ, чем открытый отличается от закрытого, зачем они нужны и что умеют — на эти и связанные вопросы здесь ответа нет. Кому надо, тот загуглит про (а)симметричное шифрование, об этом есть множество доступных ресурсов.

Терминология
  • Пользователь — системный пользователь, то есть который создаётся на линуксе через adduser или на винде в настройках.
  • Клиент — программа, реализующая клиентскую часть протокола SSH: отправляющая запросы к SSH-серверу, пишущая вам в консоль гневные тирады из-за смены ключей, и прочее. В дистрибутивах линукса часто предустановлен клиент OpenSSH, который запускается командой ssh .
  • Сервер — соответственно программа, реализующая серверную часть SSH. Не менее часто в дистрибутивах линукса предустановлен и сервер OpenSSH, выполненный в виде демона sshd . О запуске и настройке этого демона речи не пойдёт, как это делается, читателю предлагается найти на других ресурсах.
  • Стороны — клиент и сервер.
  • Вы — вы, то есть человек, использующий клиент.
  • Админ(истратор) — человек, ответственный за сервер. Возможно, совпадает с «вами». Также это может быть некоторая автоматическая система, например, если вы используете облачные сервисы. В этом случае взаимодействие с сервером происходит через панель управления облаком.

Что такое SSH?

SSH — это сетевой протокол для защищённого управления удалёнными устройствами по незащищённому сетевому соединению. Самый примечательный сценарий использования: удалённый вход в систему и выполнение команд.

Это вольный перевод первого абзаца статьи про SSH на английской википедии. Думаю, каждый, кто открывал хоть одну ссылку про SSH в гугле, знает об этом.

Чуть менее тривиально (написано во втором абзаце) то, что на самом деле SSH состоит из трёх более или менее независимых протоколов: протокол транспортного уровня, протокол аутентификации, и протокол соединения. Возможно, называть их прямо отдельными протоколами — слишком громкие слова, и можно было бы считать, что это просто три стадии работы протокола. Но так их обзывают в спецификации, а чем я хуже непонятно. Кстати, спецификация у каждого из них своя: RFC 4253, RFC 4252 и RFC 4254 соответственно, за подробностями можно и нужно обращаться к этим ссылкам.

Обычно на практике разделение на три протокола нечасто упоминается, но, чтобы понять, когда и зачем какой ключ используется, это довольно важно. Поэтому далее каждый из этих протоколов разберём отдельно.

Акт 1. Протокол транспортного уровня

Сцена 1. Установка защищённого соединения

Первый этап в работе SSH — наладить защищённый канал связи. Внимание, спойлер: позднее, например если используется аутентификация по паролю, мы будем отправлять по сети пароль голым текстом (а как иначе сервер сможет сравнить пароль с хешем, который хранит у себя?), либо не пароль так ещё кучу всякой конфиденциальной информации. Поэтому нужно осуществить некоторые танцы с бубном, чтобы кто попало эти данные не прочитал. Это, по-моему, самый сложный из трёх протоколов, так как содержит множество хитрых фикусов и рассуждений о безопасности.

Итак, первое, что делают стороны после того, как между устройствами установлено сетевое соединение (а SSH обычно работает поверх TCP, так что обычно после того, как налажено соединение TCP) — отправляют друг другу версию своего ПО и самого протокола SSH, которую хотят использовать (на момент написания статьи актуальна версия 2.0). Далее они обмениваются списками поддерживаемых алгоритмов шифрования (и не только).

Разработчики SSH предусмотрели, что, с одной стороны, алгоритмы шифрования, как и всё в жизни, со временем выходят из моды (точнее в них находят уязвимости), а с другой, не все разработчики клиентов/серверов SSH способны поддерживать все существующие алгоритмы. Поэтому и нужен шаг, на котором стороны договариваются об используемых алгоритмах. Сколько же алгоритмов и для каких конкретных целей нам понадобится? Не один и даже не два.

Первый алгоритм — алгоритм сжатия. Самый скучный, им просто сжимается каждое отправленное сообщение ради экономии трафика.

Во-первых, алгоритмов сжатия может быть выбрано два: один для сообщений от клиента к серверу, второй от сервера к клиенту. Конкретно для сжатия возможность выбрать два алгоритма не особо важна, всё равно почти всегда используется gzip в обе стороны. Но такая же возможность есть для некоторых других алгоритмов, для которых она может быть более актуальной (далее указано, для каких).

Во-вторых, на самом деле стороны договариваются одновременно обо всех алгоритмах, а «первым» я его назвал в целях красоты повествования. Вообще всё, что описано далее про протокол транспортного уровня, происходит всего за 3-4 обмена сообщениями между клиентом и сервером (то бишь всего за 6-8 отправленных сообщений). Так что по длине текста статьи не стоит делать вывод, что все проверки и обмены ключами и алгоритмами занимают большое количество шагов, это не так. В разработке протокола старались минимизировать количество необходимых сетевых взаимодействий.

В SSH слова «соединение защищено», помимо прочего, значат, что все отправляемые сообщения подвергаются симметричному шифрованию. То есть и у сервера, и у клиента есть (обычно) одинаковый ключ симметричного шифрования, который может и зашифровать, и расшифровать любое сообщение. Симметричные шифры бывают разные, поэтому второй алгоритм, о котором договариваются стороны: алгоритм симметричного шифрования (encryption algorithm).

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

Вопрос: как так сделать, чтобы клиент и сервер, изначально общаясь по незащищённому соединению, смогли договориться о ключе симметричного шифрования, и при этом никто кроме клиента и сервера не узнал этот ключ? Ответ: использовать хитроумный алгоритм обмена ключами (англ. key exchange algorithm, он же kex algorithm). Это третий алгоритм, о котором договариваются стороны.

Конкретные алгоритмы обмена ключами — это вариации на тему алгоритма Диффи-Хеллмана. На английской википедии есть очень наглядная картинка (приведена ниже), где в роли ключей выступают цвета. Сначала стороны договариваются о некотором открытом ключе (обычно клиент его генерирует и отправляет серверу по незащищённому соединению, на картинке общим ключом является жёлтый цвет). Затем каждая сторона создаёт свой закрытый ключ (на картинке цвет заката и морской волны в моей интерпретации ��). Он каким-то образом объединяется с открытым ключом (в примере с цветами — смешивается, а вообще, то, как ключи объединяются, и как в принципе генерируются, зависит от конкретного выбранного алгоритма обмена ключами), и результат отправляется другой стороне.

Затем каждая сторона объединяет уже полученный чужой результат со своим закрытым ключом, и в итоге, благодаря магии математики, оказывается, что у обеих сторон вышло одно и то же — общий секретный ключ. Далее я не буду выделять его как один из используемых ключей, потому что это всего лишь промежуточное значение, которое используется для генерации ключей, делающих более осмысленные вещи. Тут вопрос терминологии: в английском этот секретный ключ даже ключом не называется, там это просто «shared secret».

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

Иллюстрация работы алгоритма Диффи-Хеллмана.

Однако только симметричного шифрования недостаточно для защищённого соединения. Нужен ещё уже четвёртый алгоритм имитовставки (mac algorithm), которому нужен ключ имитовставки (integrity key). Он настолько же важный и базовый, как алгоритм симметричного шифрования, и введение имитовставки, так же, как и шифрование, обычно происходит под капотом у программ-реализаций, а рядовой разработчик о них не задумывается. Но если, говоря о шифровании, я могу рассчитывать, что большинство знакомы с его принципами, то имитовставка менее общеизвестна. Поэтому позволю себе вынести подробности о ней в спойлер для любопытного читателя.

Почему же шифра недостаточно? Шифр защищает от возможности прочитать содержимое сообщения, но не защищает от того, чтобы изменить его. Да, злоумышленник не знает ключ шифрования, так что скорее всего не сможет подменить сообщение на что-либо осмысленное, то есть, например, не сможет заставить сервер выполнить конкретную команду (и то не факт, если очень умный, может и сможет). Но он точно может намусорить: поменять какой-нибудь байт, и на сервер придёт мусорное сообщение, а сервер подумает, что клиент это и имел в виду. Последствия у такого тоже могут быть самые разные, в лучшем случае просто команда клиента не выполнится, и клиенту вернётся сообщение с ошибкой.

Но SSH же работает поверх TCP, который гарантирует целостность данных? Он включает контрольную сумму, которая не позволит просто так изменить сообщение? Не совсем. TCP защищает от случайных изменений пакета. Злоумышленник же, поменяв содержимое сообщения, может запросто пересчитать контрольную сумму, и подменить и её: ведь шифруются только данные, на уровне протокола SSH, а данные всех протоколов, поверх которых SSH работает, не шифруются.

Поэтому для предотвращения таких вмешательств в ход истории существует имитовставка (англ. MAC — message authentication code). Это набор байтов, который генерируется из содержимого сообщения и ключа имитовставки (integrity key), и дописывается к концу сообщения. Используя этот ключ и содержимое сообщения, каждая сторона может проверить, что оно дошло без изменений. Ключ хранится в секрете и (обычно) одинаковый у сервера и клиента, всё как с симметричным шифрованием. Таким образом, если злоумышленник подменит какие-то байты, сервер заметит подвих и не станет обрабатывать изменённое сообщение.

Сам ключ имитовставки генерируется аналогично ключу симметричного шифрования — как хеш секретного ключа, полученного из алгоритма обмена ключами, и некоторой информации, известной обеим сторонам. Только эта дополнительная информация разная для генерации ключа имитовставки и симметричного шифрования, поэтому и ключи получаются разные. От каких именно данных считается хеш для всех ключей, написано в RFC.

Алгоритмов имитовставки (а, следовательно, и ключей имитовставки) также может быть два на соединение: один от клиента к серверу, другой от сервера к клиенту.

Этих трёх алгоритмов достаточно, чтобы наладить защищённое соединение: стороны перед отправлением шифруют каждое сообщение, при получении дешифруют, а имитовставка гарантирует, что сообщение дошло в неизменном виде.

Но это не конец. На этапе обмена ключами происходит ещё одно важное действие: клиент, так сказать, проверяет сервер на вшивость. Привычно думать, что в аутентификации нуждается клиент, то есть клиент должен подтвердить свою личность, чтобы злоумышленник не проник внутрь сервера, и не натворил делов. О предотвращении делов речь пойдёт позже. Но в SSH аутентификация сервера не менее важна, ведь клиент (опять спойлер) будет отправлять ему, например, свои пароли. А все описанные ранее шаги не гарантируют, что сервер не подставной: с таким же успехом клиент мог произвести обмен ключами со злоумышленником.

Чтобы бороться с недобросовестностью сервера, используется очередной алгоритм, о котором стороны также договариваются перед обменом ключами — алгоритм цифровой подписи сервера. Это не официальное название, это я так обозвал в попытках отразить суть, в спецификации зовётся «server host key algorithm».

Сцена 2. Идентификация сервера

Пока что все описанные действия — базовые меры безопасности, которые происходят за кулисами, и с которыми редко приходится иметь дело, если вообще приходится. Теперь же речь пойдёт о вещах более приземлённых, и знание о которых важно при работе с протоколом.

У сервера изначально есть пара ключей: закрытый и открытый, они называются ключами сервера (host keys). Только на самом деле такая пара не одна: у сервера есть по паре ключей на каждый алгоритм цифровой подписи, который он поддерживает (ведь разные алгоритмы требуют разного вида ключей, вообще говоря). У сервера OpenSSH на линуксе по умолчанию ключи сервера хранятся в папке /etc/ssh в файлах с названиями ssh_host_*_key (закрытый ключ) и ssh_host_*_key.pub (соответствующий открытый ключ), вместо звёздочки пишется название алгоритма, например rsa или ecdsa . Эти ключи перед запуском SSH-сервера кладёт туда администратор: либо генерирует с нуля (например, с помощью утилиты ssh-keygen -A ), либо устанавливает из каких-то других соображений, мало ли в кармане завалялись.

Во время обмена ключами, сервер подписывает некоторую строку своим закрытым ключом (на этот момент они с клиентом уже договорились, какой алгоритм цифровой подписи использовать, поэтому ключ выбираются соответствующий этому алгоритму), и отправляет результат клиенту впридачу с открытым ключом. Эта строка составляется из некоторого набора данных, которые обеим сторонам на этот момент уже известны, вроде названия используемого протокола, версии ПО и т.п. (конкретно из каких описано в RFC), поэтому клиент может составить точно такую же строку и с помощью открытого ключа проверить достоверность подписи (возможность составить такую же строку нужна, потому что для проверки электронной подписи надо знать содержимое подписанного сообщения. Можно было бы отправлять подписанную строку клиенту вместе с ключом и подписью, но, вероятно, так решили не делать ради экономии трафика). Если подпись верна, значит сервер правда владеет закрытым ключом, соответствующим заявленному открытому.

Однако это ещё ничего не значит. С таким же успехом сервер злоумышленника мог бы сгенерировать свою пару открытый/закрытый ключ, отправить клиенту открытый, и подписать строку закрытым. Да, клиент убедится, что сервер действительно знает закрытый ключ, который соответствует отправленному открытому, но это не значит, что сервер не подставной.

Как убедиться, что сервер настоящий — это вопрос менее тривиальный, чем применить цифровую подпись. Есть разные варианты, одни более безопасные, другие менее. Чаще и проще всего это делается так: клиент хранит у себя небольшую базу данных (обычно просто в виде файла в определённом формате), которые сопоставляют каждому серверу его открытый ключ. Например, клиент OpenSSH на линуксе смотрит в файл ~/.ssh/known_hosts .

Ситуация: мне нужно ssh-нуться к машинке по адресу example.com . Для этого (будучи ответственным и волнующимся о безопасности человеком) я пойду к администратору, и узнаю у него публичный ключ сервера, запущенного на этой машинке (соответствующий алгоритму, который буду использовать для проверки сервера). Затем добавлю в known_hosts запись о том, что публичный ключ сервера example.com такой-то (формат файла подскажет гугл). Затем при каждом подключении к example.com клиент будет проверять, что отправленный сервером открытый ключ совпадает с тем, что лежит в known_hosts . Если совпадает, клиент проверит, что сервер правда владеет соответствующим закрытым ключом как описано выше. Если владеет — значит сервер точно не подставной. Небольшой нюанс: так как в known_hosts ключ сопоставляется домену, то если я хочу подключаться к этой машинке не только по домену, но и по IP адресу, этому IP адресу тоже нужно отдельной строчкой сопоставить тот же ключ.

Однако вряд ли, если вы ранее пользовались SSH, при каждом подключении к новому серверу ходили просить админа отправить ключ. Обычно при первом подключении к новому серверу клиенты SSH показывают сообщение такого характера:

The authenticity of host '. ' can't be established. ED25519 key fingerprint is SHA256:noP2S4gaQmKTIO8cHHg4ju3QptLSo6MEgCw2AiLwOJM. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?

Таким образом клиент говорит, что не знает, можно ли доверять этому серверу, и оставляет это на ваше усмотрение. Как можно действовать:

  • Набрать no и отменить подключение.
  • Набрать yes : тогда клиент автоматически добавит полученный открытый ключ сервера в known_hosts , сопоставив его домену, к которому пытались подключиться (обычно добавляется и сопоставление к IP адресу, соответствующему на данный момент этому домену). Перед тем, как бездумно набирать yes , можно обратить внимание, что выше выведен хеш открытого ключа. Его можно сравнить с ожидаемым хешем ключа (например, опять же, спросить у админа, какой должен быть хеш, или, если подключаетесь к машине в облаке, в панели управления облака он может быть указан).
  • Также можно ввести отпечаток (fingerprint) — это, грубо говоря, тоже хеш публичного ключа, который можно спросить у админа или скопировать из авторитетного источника, тогда клиент сам проверит, что отпечаток ключа, отправленного сервером, совпадает со введённым вами, и, если это так, добавит его в known_hosts .

Стоит отметить, что так как ключ сервера используется клиентом для идентификации, если он в какой-то момент изменится (например, если на сервере переустановили SSH или операционку, либо может перегенерировали ключи, из-за того, что закрытый оказался слит, а, может, просто в целях профилактики), то сервер не получится идентифицировать. С точки зрения клиента смена ключа неотличима от попытки злоумышленника подсунуть липовый ключ. Поэтому в таких случаях клиент при подключении на вас наорёт, например, как орёт OpenSSH:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the RSA key sent by the remote host is 6e:45:f9:a8:af:38:3d:a1:a5:c7:76:1d:02:f8:77:00. Please contact your system administrator. Add correct host key in /home/hostname /.ssh/known_hosts to get rid of this message.

Собственно русским по белому написано: возможно, вас пытаются злоумыслить, а, возможно, просто ключ поменялся. Узнать это можно только обратившись к администратору. Есть способы, как организовать регулярную смену ключей, но я недостаточно квалифицирован, чтобы их описывать. Любопытный читатель загуглит «ssh key rotation».

Хранить публичный ключ вкупе с доменом — не единственный способ идентификации сервера, ещё можно, например, использовать сертификаты: тогда сервер перед обменом ключами отправит свой сертификат, который клиент сможет проверить на достоверность. Но о них, возможно, в другой раз.

Итого

После всех проделанных действий мы имеем: возможность защищённым образом передавать пакеты по незащищённой сети, и уверенность в том, что сервер не подставной. Для этого у нас есть

  1. Ключ сервера: закрытый хранится только на сервере, открытый стороны используют в начале соединения для проверки личности сервера, и после этого больше не используют.
  2. Ключ симметричного шифрования и ключ имитовставки: есть у обеих сторон, хранятся только в памяти и генерируются заново при каждом подключении (и, вообще говоря, могут меняться в течение соединения. Для этого существует процедура повторного обмена ключами — key re-exchange — но это детали). Нужны для работы защищённого соединения. Разработчик обычно с ними дела не имеет, работа с ними происходит под капотом.

Обращу внимание, что пока что речь ни о каком ключе клиента не шла. Тот самый id_rsa.pub , который вечно нужно генерировать и кому-то отправлять, на текущий момент ещё не использовался.

Акт 2. Протокол аутентификации

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

Простейший способ аутентифицировать клиента: не аутентифицировать клиента. Да, можно настроить сервер для некоторых пользователей так, что как только соединение установлено, считается, что клиент молодец, и сразу может от имени этих пользователей выполнять команды/делать что там SSH ещё умеет делать. Под каким пользователем нужно подключиться, вы выбираете сами при подключении (пишете ssh myuser@example.com ), если для него авторизация выключена, то и ни паролей, ни ключей не понадобится. Естественно, это дико небезопасно, но в некоторых случаях можно оправдать такую схему.

Но мы не будем её оправдывать. У нас же теперь есть защищённое соединение, по которому можно передавать что угодно без страха, что кто-то левый прочитает. Поэтому чуть менее простейший способ аутентификации клиента: по паролю. Клиент просто отправляет имя пользователя, под которым хочет зайти, и пароль. Сервер где-то у себя хранит хеш пароля для каждого пользователя, под которым можно зайти (на линуксе обычно пользователи ssh совпадают с системными пользователями, соответственно пароль совпадает с паролем системного пользователя). При попытке входа пароль сравнивается с хешем, вот и сказочке конец. Возможность входа по паролю не обязательна, сервер SSH может её не поддерживать.

А вот обязательна возможность входа ещё менее простейшим, но более безопасным способом — по ключу. Здесь уже вы сами создаёте пару ключей клиента (например, с помощью утилиты ssh-keygen , по умолчанию закрытый ключ она записывает в файл ~/.ssh/id_rsa , а открытый — в ~/.ssh/id_rsa.pub ), сообщаете администратору открытый ключ (при использовании ssh-keygen это id_rsa.pub ), тот добавляет его на сервер. Если запущен сервер OpenSSH на линуксе, то у каждого пользователя на сервере в домашней папке есть файл ~/.ssh/auhorized_keys : администратор добавляет ключ клиента в authorized_keys того пользователя, под которым клиент сможет входить. Можно добавить один ключ в authorized_keys нескольких пользователей, тогда вы сможете входить под всеми ними. Под каким конкретно вы пытаетесь войти — опять же, указываете при подключении, например ssh myuser@example.com .

Дальше всё как было при идентификации сервера: клиент составляет строку (из данных, которые сервер тоже знает, конкретная строка описана в спецификации), подписывает закрытым ключом и отправляет подпись серверу вместе с открытым ключом, а также именем пользователя, под которым хочет войти (допустим, myuser ). Сервер проверяет, что открытый ключ ему известен (OpenSSH на линуксе смотрит, что он указан в файле /home/myuser/.ssh/authorized_keys ), составляет такую же строку, и проверяет достоверность подписи. Если всё совпало — клиент идентифицирован, и можно принимать от него команды/файлы/что угодно.

Важно! Ни в коем случае нельзя никому сообщать свой закрытый ключ (по умолчанию ~/.ssh/id_rsa без расширения .pub ). Это всё равно, что рассказать свой пароль: сервер не может отличить вас от злоумышленника, имеющего ваш закрытый ключ.

Акт 3. Протокол соединения

На этом этапе, защищённое соединение установлено, клиент подтвердил личность сервера, а сервер — клиента. Протокол соединения работает уже на прикладном уровне: если SSH используется для запуска команд в терминале, он описывает, как передавать сами команды и настройки терминала, если для передачи файлов — процесс передачи файлов. Это наименее интересная для меня часть SSH, так что в подробности вдаваться не буду. Просто определяется какой-то набор сообщений: как запустить команду на удалённом устройстве, как сообщить серверу, что на клиенте изменились размеры окна терминала, и т.д. и т.п.

Резюме

При установке соединения в SSH используются следующие ключи:

  • Ключ сервера — концептуально это ключ цифровой подписи, нужен для проверки личности сервера клиентом. Не используется для шифрования.
  • Ключ клиента — концептуально это ключ цифровой подписи, нужен для проверки личности клиента сервером. Не используется для шифрования. Вообще говоря, необходим только если используется аутентификация по ключу. Если аутентификации нет, или она по паролю, или как-то ещё (SSH подразумевает возможную реализацию иных методов), этот ключ вообще не нужен.
  • Ключ синхронного шифрования и ключ имитовставки — меняются при каждом подключении, могут меняться в течение сессии, используются для защиты соединения.

Если вы используете OpenSSH на линуксе, то вот список основных файлов, которые используются. На клиенте:

  • ~/.ssh/id_rsa — закрытый ключ клиента, который никому нельзя сообщать.
  • ~/.ssh/id_rsa.pub — открытый ключ клиента, который администратор добавляет на сервер, чтобы вы получили доступ.
  • ~/.ssh/known_hosts — список, сопоставляющий доменам/IP адресам серверов их открытые ключи. Используется чтобы удостовериться, что сервер не подставной.
  • ~/.ssh/config , /etc/ssh/ssh_config — в статье не упоминался, но это настройки клиента SSH, подробнее, что можно настроить, расскажет man ssh_config .
  • /etc/ssh/ssh_host_*_key — закрытые ключи сервера, по ключу на каждый поддерживаемый алгоритм цифровой подписи.
  • /etc/ssh/ssh_host_*_key.pub — открытые ключи сервера.
  • /home/[user]/.ssh/authorized_keys — список открытых ключей клиентов, которым разрешено входить под пользователем [user] .
  • /etc/ssh/sshd_config — настройки сервера, подробнее в man sshd_config .

Естественно, здесь опущены разные мелочи, не расписаны принципы ротации ключей, использования сертификатов, и прочее прочее. Но, надеюсь, статья будет полезной для начинающих рыбок в море сетевых протоколов.

  • ssh
  • ключи
  • ключи шифрования
  • криптография
  • протоколы
  • сетевые протоколы
  • сетевые технологии*

Как посчитать имитовставку mac функциями openssl

Модуль pgcrypto предоставляет криптографические функции для Postgres Pro .

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

F.34.1. Стандартные функции хеширования

F.34.1.1. digest()
digest(data text, type text) returns bytea digest(data bytea, type text) returns bytea

Вычисляет двоичный хеш данных ( data ). Параметр type выбирает используемый алгоритм. Поддерживаются стандартные алгоритмы: md5 , sha1 , sha224 , sha256 , sha384 и sha512 . Если модуль pgcrypto собирался с OpenSSL , становятся доступны и другие алгоритмы, как описано в Таблице F.24.

Если вы хотите получить дайджест в виде шестнадцатеричной строки, примените encode() к результату. Например:

CREATE OR REPLACE FUNCTION sha1(bytea) returns text AS $$ SELECT encode(digest($1, 'sha1'), 'hex') $$ LANGUAGE SQL STRICT IMMUTABLE;
F.34.1.2. hmac()
hmac(data text, key text, type text) returns bytea hmac(data bytea, key bytea, type text) returns bytea

Вычисляет имитовставку на основе хеша для данных data с ключом key . Параметр type имеет то же значение, что и для digest() .

Эта функция похожа на digest() , но вычислить хеш с ней можно, только зная ключ. Это защищает от сценария подмены данных и хеша вместе с ними.

Если размер ключа больше размера блока хеша, он сначала хешируется, а затем используется в качестве ключа хеширования данных.

F.34.2. Функции хеширования пароля

Функции crypt() и gen_salt() разработаны специально для хеширования паролей. Функция crypt() выполняет хеширование, а gen_salt() подготавливает параметры алгоритма для неё.

Алгоритмы в crypt() отличаются от обычных алгоритмов хеширования MD5 и SHA1 в следующих аспектах:

Они медленные. Так как объём данных невелик, это единственный способ усложнить перебор паролей.

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

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

В Таблице F.21 перечислены алгоритмы, поддерживаемые функцией crypt() .

Таблица F.21. Алгоритмы, которые поддерживает crypt()

Алгоритм Макс. длина пароля Адаптивный? Размер соли (бит) Размер результата Описание
bf 72 да 128 60 На базе Blowfish, вариация 2a
md5 без ограничений нет 48 34 crypt на базе MD5
xdes 8 да 24 20 Расширенный DES
des 8 нет 12 13 Изначальный crypt из UNIX
F.34.2.1. crypt()
crypt(password text, salt text) returns text

Вычисляет хеш пароля ( password ) в стиле crypt(3). Для сохранения нового пароля необходимо вызвать gen_salt() , чтобы сгенерировать новое значение соли ( salt ). Для проверки пароля нужно передать сохранённое значение хеша в параметре salt и проверить, соответствует ли результат сохранённому значению.

Пример установки нового пароля:

UPDATE . SET pswhash = crypt('new password', gen_salt('md5'));

Пример проверки пароля:

SELECT (pswhash = crypt('entered password', pswhash)) AS pswmatch FROM . ;

Этот запрос возвращает true , если введённый пароль правильный.

F.34.2.2. gen_salt()
gen_salt(type text [, iter_count integer ]) returns text

Вычисляет новое случайное значение соли для функции crypt() . Строка соли также говорит crypt() , какой алгоритм использовать.

Параметр type задаёт алгоритм хеширования. Принимаются следующие варианты: des , xdes , md5 и bf .

Параметр iter_count позволяет пользователю указать счётчик итераций для алгоритма, который его принимает. Чем больше это число, тем больше времени уйдёт на вычисление хеша пароля, а значит, тем больше времени понадобится, чтобы взломать его. Хотя со слишком большим значением время вычисления хеша может вырасти до нескольких лет — это вряд ли практично. Когда параметр iter_count опускается, применяется количество итераций по умолчанию. Множество допустимых значений для iter_count зависит от алгоритма, как показано в Таблице F.22.

Таблица F.22. Счётчики итераций для crypt()

Алгоритм По умолчанию Мин. Макс.
xdes 725 1 16777215
bf 6 4 31

Для xdes есть дополнительное ограничение: счётчик итераций должен быть нечётным.

При выборе подходящего числа итераций учтите, что оригинальный алгоритм DES crypt был рассчитан так, чтобы выдавать 4 хеша в секунду на компьютерах того времени. Если за секунду будет вычисляться меньше 4 хешей, скорее всего, возникнут определённые неудобства при пользовании. С другой стороны, скорость больше, чем 100 хешей в секунду, вероятно, будет слишком высокой.

В Таблице F.23 дана сводка относительной скорости различных алгоритмов хеширования. В таблице показано, сколько времени уйдёт на перебор всех комбинацией символов в восьмисимвольном пароле, в предположении, что пароль содержит только буквы в нижнем регистре, либо буквы в верхнем и нижнем регистре, а также цифры. В строках crypt-bf числа после косой черты показывают значение параметра iter_count функции gen_salt .

Таблица F.23. Скорости алгоритмов хеширования

Алгоритм Хешей/сек. Для [a-z] Для [A-Za-z0-9] Длительность относительно md5
crypt-bf/8 1792 4 года 3927 лет 100k
crypt-bf/7 3648 2 года 1929 лет 50k
crypt-bf/6 7168 1 год 982 лет 25k
crypt-bf/5 13504 188 дней 521 лет 12.5k
crypt-md5 171584 15 дней 41 год 1k
crypt-des 23221568 157.5 минут 108 дней 7
sha1 37774272 90 минут 68 дней 4
md5 (хеш) 150085504 22.5 минут 17 дней 1

Для расчётов использовался процессор Intel Mobile Core i3.

Показатели алгоритмов crypt-des и crypt-md5 взяты из вывода теста программы John the Ripper v1.6.38.

Показатели md5 получены программой mdcrack 1.2.

Показатели sha1 получены программой lcrack-20031130-beta.

Заметьте, что вариант « перепробовать все комбинации » не вполне реалистичен. Обычно перебор паролей производится с применением словарей, которые содержат и обычные слова, и их различные видоизменения. Поэтому даже похожие на слова пароли обычно можно подобрать быстрее, чем за указанное время, тогда как 6-символьный несловесный пароль может избежать взлома. А может и не избежать.

F.34.3. Функции шифрования на базе PGP

Функции, описанные здесь, реализуют часть стандарта OpenPGP (RFC 4880), относящуюся к шифрованию. Они поддерживают шифрование как с симметричным, так и с закрытым ключом.

Зашифрованное PGP сообщение состоит из 2 частей или пакетов:

Пакет, содержащий сеансовый ключ — либо симметричный, либо открытый (в зашифрованном виде).

При шифровании с симметричным ключом (то есть, паролем):

Заданный пароль хешируется по алгоритму String2Key (S2K). Этот алгоритм подобен алгоритмам crypt() — специально замедлен и добавляет случайную соль — но на выход выдаёт двоичный ключ полной длины.

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

При шифровании с открытым ключом:

Генерируется новый случайный сеансовый ключ.

В любом случае данные, которые должны быть зашифрованы, обрабатываются так:

Необязательная подготовка данных: сжатие, перекодировка в UTF-8 и/или преобразование концов строк.

Перед данными добавляется блок случайных байт. Это равносильно использованию случайного вектора инициализации.

В конце добавляется хеш SHA1 случайного префикса и данных.

F.34.3.1. pgp_sym_encrypt()
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea

Шифрует данные ( data ) симметричным ключом PGP psw . В options могут передаваться криптографические параметры, описанные ниже.

F.34.3.2. pgp_sym_decrypt()
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea

Расшифровывает сообщение, зашифрованное симметричным ключом PGP.

Расшифровывать данные bytea функцией pgp_sym_decrypt запрещено. Это ограничение введено, чтобы не допустить вывода некорректных символьных данных. Расшифровывать изначально текстовые данные с помощью pgp_sym_decrypt_bytea можно без ограничений.

Аргумент options может содержать криптографические параметры, описанные ниже.

F.34.3.3. pgp_pub_encrypt()
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea

Зашифровывает данные ( data ) открытым ключом PGP ( key ). Если передать этой функции закрытый ключ, она выдаст ошибку.

Аргумент options может содержать криптографические параметры, описанные ниже.

F.34.3.4. pgp_pub_decrypt()
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea

Расшифровывает сообщение, зашифрованное открытым ключом. В key должен передаваться закрытый ключ, соответствующий открытому ключу, применяющемуся при шифровании. Если секретный ключ защищён паролем, этот пароль нужно передать в параметре psw . Если пароля нет, но необходимо передать криптографические параметры, вы должны передать пустой пароль.

Расшифровывать данные bytea функцией pgp_pub_decrypt запрещено. Это ограничение введено, чтобы не допустить вывода недопустимых символьных данных. Расшифровывать изначально текстовые данные с помощью pgp_pub_decrypt_bytea можно без ограничений.

Аргумент options может содержать криптографические параметры, описанные ниже.

F.34.3.5. pgp_key_id()
pgp_key_id(bytea) returns text

pgp_key_id извлекает идентификатор ключа из открытого или закрытого ключа PGP. Она также может выдать идентификатор ключа, которым были зашифрованы данные, если ей передаётся зашифрованное сообщение.

Она может выдать два специальных идентификатора ключа:

Сообщение зашифровано симметричным ключом.

Заметьте, что разные ключи могут иметь одинаковый идентификатор. Это редкое, но не невероятное явление. В таком случае клиентское приложение должно пытаться расшифровать данные с каждым ключом, пока не найдёт подходящий — примерно так же, как и с ANYKEY .

F.34.3.6. armor() , dearmor()
armor(data bytea [ , keys text[], values text[] ]) returns text dearmor(data text) returns bytea

Эти функции переводят двоичные данные в/из формата PGP «ASCII Armor», по сути представляющий собой кодировку Base64 с контрольными суммами и дополнительным форматированием.

Если задаются массивы keys и values , для каждой пары ключ/значения в формат Armor добавляется заголовок Armor. Оба массива должны быть одномерными и иметь одинаковую длину. Задаваемые ключи и значения могут содержать только символы ASCII.

F.34.3.7. pgp_armor_headers
pgp_armor_headers(data text, key out text, value out text) returns setof record

Функция pgp_armor_headers() извлекает заголовки Armor из параметра data . Она возвращает набор строк с двумя столбцами, key и value. Если в ключах или значениях оказываются символы не ASCII, они воспринимаются как UTF-8.

F.34.3.8. Параметры функций PGP

Имена параметров подобны принятым в GnuPG. Значение параметра должно задаваться после знака равно; друг от друга параметры отделяются запятыми. Например:

pgp_sym_encrypt(data, psw, 'compress-algo=1, cipher-algo=aes256')

Все эти параметры, кроме convert-crlf , применяются только к функциям шифрования. Функции расшифровывания получают параметры из данных PGP.

Вероятно, самые интересные параметры — это compress-algo и unicode-mode . Остальные должны иметь достаточно адекватные значения по умолчанию.

F.34.3.8.1. cipher-algo

Выбирает алгоритм шифрования.

Значения: bf, aes128, aes192, aes256 (только OpenSSL: 3des , cast5 )
По умолчанию: aes128
Применим к: pgp_sym_encrypt, pgp_pub_encrypt

F.34.3.8.2. compress-algo

Выбирает алгоритм сжатия. Принимается, только если Postgres Pro собран с zlib.

Значения:
0 — без сжатия
1 — сжатие ZIP
2 — сжатие ZLIB (= ZIP плюс метаданные и CRC блоков)
По умолчанию: 0
Применим к: pgp_sym_encrypt, pgp_pub_encrypt

F.34.3.8.3. compress-level

Определяет уровень сжатия. Чем больше уровень, тем меньшего объёма результат, но длительнее процесс. Значение 0 отключает сжатие.

Значения: 0, 1-9
По умолчанию: 6
Применим к: pgp_sym_encrypt, pgp_pub_encrypt

F.34.3.8.4. convert-crlf

Определяет, преобразовывать ли \n в \r\n при шифровании и \r\n в \n при дешифровании. В RFC 4880 требуется, чтобы текстовые данные хранились с переводами строк в виде \r\n . Воспользуйтесь этим параметром, чтобы поведение полностью соответствовало RFC.

Значения: 0, 1
По умолчанию: 0
Применим к: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt

F.34.3.8.5. disable-mdc

Не защищать данные хешем SHA-1. Единственная разумная причина использовать этот параметр — добиться совместимости с древними программами PGP, вышедшими до того, как в RFC 4880 была предусмотрена защита пакетов с SHA-1. Все последние реализации с gnupg.org и pgp.com прекрасно поддерживают это.

Значения: 0, 1
По умолчанию: 0
Применим к: pgp_sym_encrypt, pgp_pub_encrypt

F.34.3.8.6. sess-key

Использовать отдельный сеансовый ключ. Для шифрования с открытым ключом всегда используется отдельный сеансовый ключ; этот параметр предназначен для шифрования с симметричным ключом, которое по умолчанию использует непосредственно ключ S2K.

Значения: 0, 1
По умолчанию: 0
Применим к: pgp_sym_encrypt

F.34.3.8.7. s2k-mode

Режим алгоритма S2K.

Значения:
0 — Без соли. Опасно!
1 — С солью, но с фиксированным числом итераций.
3 — С переменным числом итераций.
По умолчанию: 3
Применим к: pgp_sym_encrypt

F.34.3.8.8. s2k-count

Число итераций для алгоритма S2K. Оно должно быть не меньше 1024 и не больше 65011712.

По умолчанию: случайное значение между 65536 и 253952
Применим к: pgp_sym_encrypt, только с s2k-mode=3

F.34.3.8.9. s2k-digest-algo

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

Значения: md5, sha1
По умолчанию: sha1
Применим к: pgp_sym_encrypt

F.34.3.8.10. s2k-cipher-algo

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

Значения: bf, aes, aes128, aes192, aes256
По умолчанию: используется cipher-algo
Применим к: pgp_sym_encrypt

F.34.3.8.11. unicode-mode

Определяет, преобразовывать ли текстовые данные из внутренней кодировки базы данных в UTF-8 и обратно. Если кодировка базы уже UTF-8, перекодировка не производится, но сообщение помечается как UTF-8. Без данного параметра этого не происходит.

Значения: 0, 1
По умолчанию: 0
Применим к: pgp_sym_encrypt, pgp_pub_encrypt

F.34.3.9. Формирование ключей PGP с применением GnuPG

Формирование нового ключа:

gpg --gen-key

Предпочитаемый тип ключей: « DSA and Elgamal » .

Для шифрования RSA вы должны создать главный ключ либо DSA, либо RSA только для подписания, а затем добавить подключ для шифрования, выполнив команду gpg —edit-key .

Просмотр списка ключей:

gpg --list-secret-keys

Экспорт открытого ключа в формате «ASCII Armor»:

gpg -a --export KEYID > public.key

Экспорт закрытого ключа в формате «ASCII Armor»:

gpg -a --export-secret-keys KEYID > secret.key

Прежде чем передавать эти ключи функциям PGP, вы должны применить функцию dearmor() к этим ключам. Либо, если вы можете обработать двоичные данные, уберите -a из команды.

Дополнительную информацию вы можете получить в руководстве man gpg , The GNU Privacy Handbook (Руководство GNU по обеспечению конфиденциальности) и другой документации на сайте https://www.gnupg.org/.

F.34.3.10. Ограничения кода PGP

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

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

F.34.4. Низкоуровневые функции шифрования

Эти функции выполняют только шифрование данных; они не предоставляют расширенные возможности шифрования PGP. Таким образом, с ними связаны следующие проблемы:

Они используют ключ пользователя непосредственно в качестве ключа шифрования.

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

Они рассчитаны на то, что пользователи будут управлять всеми параметрами шифрования самостоятельно, даже вектором инициализации.

Поэтому с появлением поддержки шифрования PGP использовать низкоуровневые функции шифрования не рекомендуется.

encrypt(data bytea, key bytea, type text) returns bytea decrypt(data bytea, key bytea, type text) returns bytea encrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea

Эти функции зашифровывают/расшифровывают данные, применяя метод шифрования, заданный параметром type . Строка type имеет следующий формат:

алгоритм [ - режим ] [ /pad: дозаполнение ]

где допустимый алгоритм :

cbc — следующий блок зависит от предыдущего (по умолчанию)

и допустимое дозаполнение :

pkcs — данные могут быть любой длины (по умолчанию)

Так что, например, эти вызовы равнозначны:

encrypt(data, 'fooz', 'bf') encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')

Для функций encrypt_iv и decrypt_iv параметр iv задаёт начальное значение для режима CBC; для ECB он игнорируется. Оно обрезается или дополняется нулями, если его размер не равен ровно размеру блока. В функциях без этого параметра оно по умолчанию заполняется нулями.

F.34.5. Функции получения случайных данных

gen_random_bytes(count integer) returns bytea

Возвращает криптографически стойкие случайные байты в количестве count . За один вызов можно получить максимум 1024 байт. Это ограничение предотвращает исчерпание пула энтропии.

gen_random_uuid() returns uuid

Возвращает UUID версии 4 (случайный). (Эта функция в данном модуле считается устаревшей, она вызывает одноимённую функцию ядра.)

Карточная ОС Рутокен

Карточная операционная система Рутокен

  • Реестр российского ПО
  • ISO/IEC 7816-4

Работоспособность смарт-карт и токенов обеспечивается специальной программой, записанной в память аппаратного устройства, — карточной операционной системой (КОС).

Карточная ОС отвечает за обработку команд смарт-карты, работу ее файловой системы и оперативной памяти, выполнение «приложений». Приложениями в данном случае, например, можно считать криптографические алгоритмы. Для обеспечения совместимости с приложениями операционные системы смарт-карт должны соответствовать определенным стандартам, регламентирующим систему команд, файловую систему и т. п. Основной международный стандарт, использующийся в смарт-картах, — ISO/IEC 7816-4 . Этому стандарту соответствует и КОС Рутокен.

Характеристики и возможности

Сердцем и мозгом основных продуктов линейки Рутокен служат 32-разрядные высокопроизводительные микроконтроллеры архитектуры ARM. Благодаря значительной вычислительной мощности процессора ресурсоемкие вычисления, такие как генерация ключевых пар, вычисление и проверка электронной подписи выполняются достаточно быстро — даже на тех моделях микроконтроллеров, где отсутствуют специальные ускорители криптографических операций.

В аппаратных решениях Рутокен используются современные защищенные микроконтроллеры с большим объемом энергонезависимой памяти для хранения пользовательских данных.

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

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

Взаимодействие со смарт-картами и токенами обеспечивается при помощи набора специальных команд — программного интерфейса. Команды этого интерфейса формируются пользовательскими приложениями или терминалами и передаются в смарт-карту, где обрабатываются карточной ОС. Результат обработки команды в виде ответа возвращается вызывающей стороне.

Совокупность команд и ответов образуют стандартный программный интерфейс смарт-карты, который называется APDU (Application Protocol Data Unit). Интерфейс APDU определен в международном стандарте ISO/IEC 7816-4. Смарт-карты поддерживают определенное подмножество команд этого стандарта, необходимое для реализации их возможностей.

Карточная ОС Рутокен поддерживает множество команд APDU-интерфейса: команды для работы с объектами в памяти смарт-карты (файлами, папками и специальными объектами), команды атутентификации пользователей, криптографические команды и т. д. Благодаря поддержке стандартизованных команд APDU-интерфейса процесс встраивания смарт-карт Рутокен в решения заказчика максимально упрощается и удешевляется.

Для хранения и обслуживания данных в памяти Рутокен, а также для разграничения доступа к ним карточная ОС Рутокен предоставляет специальную файловую систему, имеющую следующие характеристики:

  • Удовлетворяет требованиям стандарта ISO/IEC 7816-4.
  • Использует File Allocation Table (FAT) для оптимального размещения файловых объектов и для исключения эффекта фрагментации памяти.
  • Предоставляет папки (DF) и файлы (EF) для хранения и обработки информации. При этом уровень вложенности папок ограничен только объемом свободной памяти устройства, а в каждой папке можно хранить до 255 файловых объектов.
  • Для хранения ключевой информации (ключи шифрования, PIN-коды и т. п. ) предоставляются специальные файлы — Rutoken Special File (RSF-файлы), имеющие особые характеристики и обеспечивающие полную защиту секретных данных от чтения извне.
  • Каждый тип ключевой информации хранится в своей предопределенной папке, которая автоматически выбирается карточной ОС Рутокен при создании и использовании RSF-файла того или иного типа.
  • Для удобной настройки параметров криптографических операций предоставляется Security Environment — специальная структура в оперативной памяти устройства Рутокен.
  • В моделях Рутокен, имеющих внешнюю flash-память, может быть предоставлена технология поддержки Хранилищ. Эта технология обеспечивает хранение специфических объектов данных разного типа в доступной области памяти устройства — в Хранилище, с необходимым каждому типу объектов уровнем защищенности.

Карточная ОС Рутокен обеспечивает широкий спектр возможностей по аутентификации различных категорий владельцев и разделению их прав доступа:

  • Поддерживаются 3 категории владельцев: Администратор, Пользователь, Гость.
  • Поддерживаются 2 Глобальных PIN-кода — Администратора и Пользователя, а также до 29 Локальных PIN-кодов для защиты конкретных объектов в памяти устройства.
  • Поддерживаются комбинированные схемы аутентификации: по схеме «Администратор или Пользователь», а также аутентификация по Глобальным PIN-кодам в сочетании с аутентификацией по Локальным PIN-кодам.
  • Минимальный размер каждого PIN-кода может быть настроен индивидуально.
  • Поддерживается аутентификация по сложным правилам — путем задания сложной логической комбинации условий выполнения защищенной операции. С помощью сложных правил можно сконструировать “нестандартные” условия выполнения операции: например, выполнение операции после аутентификации любым PIN-кодом из заданной группы, либо по пересечению (объединению) двух или более заданных групп и т. п.
  • Поддерживается внешняя аутентификация (аутентификация внешнего ПО).
  • Качество использующихся PIN-кодов можно контролировать при помощи гибко настраиваемых аппаратных политики качества PIN-кодов, таких как:
    • Ограничение минимальной длины PIN-кода;
    • Ограничение использования PIN-кодов по умолчанию;
    • Запрет PIN-кода, состоящего из одного повторяющегося символа;
    • Требования по наличию в PIN-коде: прописных и строчных букв, цифр, специальных символов;
    • Контроль истории ранее установленных значений PIN-кода, и т. д.

    Карточная ОС Рутокен позволяет выполнять широкий спектр криптографических операций на хранящейся в файловой системе ключевой информации:

    • Генерация ключевых пар, формирование и проверка электронной подписи по алгоритмам ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001.
    • Вычисление значения хэш-функции данных по алгоритмам ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94, в том числе с возможностью последующего формирования электронной подписи.
    • Генерация и импорт ключей шифрования, шифрование данных в стандартных режимах работы алгоритмов ГОСТ Р 34.12-2015 / ГОСТ 34.12-2018 («Кузнечик», «Магма»), ГОСТ 28147-89, вычисление и проверка криптографической контрольной суммы данных (имитовставки ГОСТ).
    • Выработка сессионных ключей (ключей парной связи) по схемам VKO GOST R 34.10-2001 (RFC4357) и VKO GOST R 34.10-2012.
    • Генерация последовательности случайных чисел требуемой длины.
    • Опционально — поддержка зарубежных криптографических алгоритмов: RSA (с ключами размером до 4096 бит), ECDSA (с кривыми secp256k1 и secp256r1).

    Карточная ОС Рутокен обеспечивает выполнение всех криптографических операций строго «на борту» устройства Рутокен, без необходимости выгрузки ключевой информации наружу. Как следствие, закрытые и симметричные ключи никогда не покидают пределы устройства Рутокен. Таким образом, исключается возможность компрометации ключа и увеличивается общая безопасность информационной системы.

    Лицензирование и цены

    При поставке карточной ОС Рутокен применяется гибкая системы лицензирования и ценообразования.

    Стандартно карточная ОС Рутокен поставляется в составе программно-аппаратного комплекса (ПАК) Рутокен: смарт-карт или USB-токенов различных форм-факторов. В этом случае стоимость КОС Рутокен включается в стоимость этого ПАК.

    Кроме того, карточная ОС Рутокен может лицензироваться для использования в ПАК технологических партнеров компании «Актив». В этом случае политика лицензирования и стоимость КОС Рутокен определяется индивидуально.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *