Кстати, в продолжение Certificate Transparency. Регулярно приходится сталкиваться с вопросами или предположениями относительно того или иного TLS-сертификата, которые сопровождаются недостаточным количеством “иллюстративных” данных. (Эта записка – рекомендации для обычных пользователей.)

Предположим, что вы где-то встретили или обнаружили “подозрительный TLS-сертификат” и хотите получить комментарии специалиста про этот сертификат. Как поступить?

Прежде всего: необходимо сохранить сам файл сертификата непосредственно и полностью. Скриншот окна Windows с информацией “об издателе” и со сроками действия – никак не позволяет что-то содержательное сказать о сертификате: по этим данным даже нельзя судить о том, разные сертификаты вы просматриваете или один и тот же. Сохранить сертификат можно при помощи функции экспорта. К сожалению, реализации этой функции существенно различаются от приложения к приложению. Например, в браузере нужно кликнуть на “замочек в адресной строке” или на вкладку панели веб-разработчика, соответствующую настройкам безопасности сайта, или ещё куда-то, но логика данного действия общая – нужно найти, где сертификат сервера (веб-сайта) экспортируется в файл. Файл может иметь разные форматы (Base64, “двоичный”) и разные расширения в имени (.pem, .cer, .der, .bin, .cert и др.), но это, обычно, не важно – для специалиста это редко является проблемой. Главное – получить сам сертификат полностью в файле. Если функция экспорта позволяет сохранить “цепочку сертификатов” – тем лучше, сохраните цепочку. Основная причина, по которой нужен именно файл, в том, что сертификат содержит значение подписи, а это значение является доказательством того, что сертификат действительно был выпущен и подписан с использованием того или иного ключа. Кроме того – можно удобным способом просматривать все поля сертификата (серийный номер, расширения, ключ и пр.).

Если вам по каким-то причинам удаётся просмотреть только значения конкретных полей сертификата, то, во-первых, нужно сразу отметить, что ценной информации будет очень мало, и, во-вторых, попытаться сохранить серийный номер, отпечаток сертификата (значение хеш-функции для сертификата), имена, – то есть, название УЦ и имя, для которого сертификат выпущен (Issuer, Subject, Subject Alternative Name), – значение ключа (или отпечаток ключа; в сертификате публикуется открытый ключ) и тип криптосистемы, значение подписи с указанием на тип криптосистемы, сроки действия и сведения о цепочке сертификатов (серийные номера, имена, отпечатки), использованной для валидации.

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



Комментировать »

На сайте ТЦИ (Технический Центр Интернет) опубликована моя статья о технологии Certificate Transparency (CT) и её роли в современном Интернете. Статья рассказывает не столько о базовых принципах построения CT (они достаточно широко известны), сколько об особенностях реального применения данной технологии – о проблемах, связанных с неверной интерпретацией значения меток в сертификатах, о полноте CT-логов.

Certificate Transparency […] лишь предоставляет инструмент для наблюдения за деятельностью УЦ, но никак не ограничивает эту деятельность на техническом уровне.



Комментировать »

Ещё о пресертификатах в Certificate Transparency (CT) и странных “свойствах”, которые возникают вокруг. TLS-сертификаты превращаются в пресертификаты после того, как добавлено специальное расширение Poison. Может показаться, что с этим расширением тоже связана проблема “курицы и яйца”, поскольку нарушать процесс валидации poison-расширение должно потому, что оно помечено как Critical (критическое), но имеет тип, неизвестный валидатору – неизвестные критические типы, согласно рекомендациям, должны приводить к тому, что сертификат считается невалидным (а вот расширения неизвестного типа, которые не помечены как критические, можно игнорировать). Если же валидатор знает тип poison-расширения, то флаг Critical уже не должен препятствовать валидации. Это так, однако проблемы тут нет: в том случае, когда валидатор распознал poison-расширение, он не должен принимать сертификат на правах валидного, так как, грубо говоря, видит, что это пресертификат (ну или можно интерпретировать иначе: наличие poison-расширения означает, что сертификат не должен использоваться так же, как и сертификат без Poison). В общем, всё же появляется неплохой шанс выстроить однозначный процесс валидации.

С пресертификатами связано множество весьма неочевидных аспектов. Так, единственный смысл в пресертификатах – это создание “костыля” для получения метки времени от сервиса CT-лога, чтобы включить эту метку в сертификат. Метка (она называется SCT) связана с конкретным пресертификатом и подписывается лог-сервисом. Но включается метка уже в сертификат, который от пресертификата отличается в некоторых деталях. Напрмер, сертификат не должен содержать poison-расширение. При валидации сертификата проверяется и SCT-метка (ну, если валидирующая сторона, – скажем, браузер, – хочет проверить метку). Понятно, что если подпись вычислена для другого набора данных (пресертификат), то она не сойдётся. Как же устроены процессы подписывания и проверки подписи SCT-метки? Они устроены непросто.

При вычислении подписи для пресертификата сервис CT-лога использует в качестве входных данных не весь сертификат, а только его “содержательную часть” (некоторое зафиксированное в структуре подмножество полей), из которой, к тому же, удаляется poison-расширение. Это, что называется, первый “сюрприз”: poison-расширение должно присутствовать в составе поступающего пресертификата не только потому, что оно и делает сертификат пресертификатом, но и потому, что иначе не сойдётся подпись УЦ на пресертификате, а подпись должен проверить сервис лога. Дописать какие-то данные в сертификат не выйдет. Однако поскольку в сертификате Poison удаляется, то и подпись в SCT нужна на данных без poison-расширения. Второй “сюрприз”: при проверке подписи SCT в сертификате – нужно восстановить содержательную часть пресертификата в точно таком виде, какой передавался в сервис CT-лога, но с учётом удаления Poison – то есть, нужно удалить “лишние” расширения (SCT-метки), а те расширения, которые останутся, должны совпасть с конфигурацией пресертифката. А поскольку такое преобразование снова удаляет из состава сертификата значение подписи, к данным сертификата, перед проверкой, вместе с другими служебными параметрами SCT, нужно присоединить отпечаток открытого ключа УЦ. Понятно, что то же самое делается и на стороне CT-лога, при формировании SCT. Так что общий алгоритм местами “макаронный”, но, тем не менее, используется. Не удивительно, что в новой версии CT пресертификатов нет.



Комментировать »

Можно ли в вебе на стороне сервера определить, какой именно версии браузер устанавливает TLS-соединение, в самом начале этого соединения? Например, для того, чтобы выбрать сертификат от подходящего УЦ (см. ниже). Хитрость в том, что привычный способ, когда браузер определяется по HTTP-заголовку User-Agent, тут не подходит: на начальном этапе установления соединения никаких HTTP-заголовков ещё нет, а вот серверный сертификат передавать нужно. И речь не про выбор сертификата на основе перечня поддерживаемых криптосистем, как это делается при настройке параллельной работы ГОСТ-алгоритмов и “обычных” алгоритмов в TLS/HTTPS – эта задача как раз решается весьма просто. Вообще, проблема находится на другом уровне: строго говоря, узнавать нужно даже не столько браузер, сколько конкретную библиотеку, реализующую TLS (так, для Firefox это будет NSS), и конкретный профиль данной библиотеки. Вообще, сделать выбор иногда можно на основе анализа состава TLS-сообщений, но так как набор этих сообщений не велик, а сам перечень может изменяться, то и точность не велика. Тем не менее, конкретная разновидность браузеров могла бы сигналить серверу, что именно такой браузер подключается. Это реализуется через дополнение TLS-сообщений, но внедрение потребует доработки TLS-стека как на стороне сервера, так и на стороне браузера.

А вот что касается именно списка поддерживаемых УЦ, то в TLS уже есть встроенный механизм, в версии 1.3 он так и называется – “certificate_authorities”. Это расширение, которое клиент может включить в состав сообщения ClienHello (начальное сообщение TLS-соединения), а сервер может обработать и – выбрать нужный сертификат, в том числе, для одной и той же криптосистемы. Вот только распространённые браузеры данное расширение не поддерживают, а если бы и поддерживали, то туда пришлось бы вписывать слишком много имён УЦ, так как в типичный дистрибутив браузера их входят многие десятки. Так что доработка, как минимум, браузера – всё равно потребуется.



Комментировать »

Цитата из моего технического описания TLS:

Весьма полезной практикой является разумное выравнивание стойкости используемых криптосистем. Например, в подавляющем большинстве случаев не имеет смысла использовать RSA-ключ длиной в 4096 бит, если ваш TLS-сервер всё ещё поддерживает SSLv3, а в качестве симметричного шифра применяет DES с 56-битным ключом.

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

Дело в том, что аутентификация с использованием ключа из сертификата происходит на начальном этапе. Заметьте, кстати, что в устаревшей схеме с “зашифрованием RSA”, проверка того, что серверу известен соответствующий сертификату секретный ключ, вообще косвенная: предполагается, что раз сервер смог прийти к одинаковым с клиентскими значениям сеансовых ключей, то у сервера сеть доступ к секретному ключу (при использовании современной схемы, с протоколом Диффи-Хеллмана, клиентом проверяется именно подпись, что несколько меняет ситуацию). Так или иначе, но после установления соединения для аутентификации трафика используются уже сеансовые ключи, а если их удалось раскрыть, то активный перехватывающий узел сможет произвольным образом подменить полезные данные внутри сессии, как если бы эти данные передавал подлинный сервер – то есть, подменить источник. Таким образом, хоть формально аутентификация и проводится с другим, стойким ключом, нестойкий сеансовый ключ уничтожает большую часть смысла такой аутентификации. Речь, естественно, про TLS, а за скобками остались пояснения о том, что раскрытие конкретного шифротекста и раскрытие конкретного ключа – разные вещи (это несколько другая история).

В TLS 1.3 криптосистема RSA для зашифрования не используется, а процесс получения сеансовых ключей (за некоторыми исключениями) основывается на протоколе Диффи-Хеллмана и состоит из нескольких этапов. Тем не менее, раскрытие сеансовых симметричных ключей и тут приводит к тому, что активный атакующий может подменить трафик, выступив вместо одной из сторон после того, как соединение установлено.



Комментировать »

Опубликовано на dxdt.ru 10 октября 2010 года – про теоретические особенности изготовления механических ключей по фотографии:

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



Комментировать »

Подписи DNSSEC в глобальном корне DNS появились в 2010 году. Это подписи криптосистемы RSA, которая сейчас считается устаревшей. Ввод DNSSEC прошёл в таком режиме, который не содержал даже механизма обновления корневых ключей – этот механизм внедрили существенно позже. Корневой ключ заменили, но криптосистема осталась той же – RSA. И вот, в 2023 году ICANN “планирует начать процесс подготовки” внедрения новых криптосистем в корневой зоне DNS: на днях опубликовали сообщение о создании рабочей группы. Можно предположить, что в корне DNS появится ECDSA, а может быть даже и что-то из разряда EdDSA (но этот вариант, конечно, вряд ли).



Комментировать »

Случайные числа, – которые, чаще, псевдослучайные, – сейчас нужны всюду. В том числе, при нормальном функционировании операционных систем, что порождает занимательные случаи. Например, мне приходилось сталкиваться со следующим “загадочным явлением”: после установки на достаточно старый, но с некоторыми аппаратными обновлениями (см. ниже, это важный момент), компьютер современной версии ОС на базе Linux (насколько помню, Debian 10), не удаётся зайти в только что сконфигурированную систему при помощи SSH с удалённого узла. SSH-сервер просто не отвечает. Локально, подключив монитор и клавиатуру, зайти можно и выглядит всё хорошо: конфигурация верная, всё работает. Самое загадочное: если после того, как кто-то повозился с локальной консолью, попробовать подключиться по SSH удалённо, то всё прекрасно работает.

Разгадка cледующая. SSH-серверу просто не хватало локальной случайности – то есть, системного источника случайных чисел (/dev/random). Дело в том, что ядро (Linux) собирает энтропию для процесса, генерирующего (псевдо)случайные числа, так сказать, с доступной аппаратуры. В более или менее современных системах проблем с обильными источниками аппаратной энтропии нет, так или иначе, а вот если в очень старую систему на процессоре Intel поставить вместо шпиндельного винчестера SSD-накопитель, да отключить клавиатуру и видеокарту, то энтропии становится мало и её съедает само ядро при загрузке себя и сопутствующих модулей (напомню, что там есть всякие хитрые методы “рандомизации адресации”, направленные, как бы, на запутывание атакующих). Так как SSH-сервер использовал блокирующий вызов для получения случайных чисел (/dev/random вместо неблокирующего /dev/urandom), то ему приходилось ждать, пока накопится достаточно энтропии. SSH-серверу случайные числа нужны для криптографических операций, поэтому он и не мог принять входящее соединение. А вот если кто-то подключил клавиатуру, да ещё повозился в консоли, то энтропии становилось больше, хватало и для SSH. Чинится это либо установкой специального пакета типа haveged, который генерирует дополнительную энтропию программно (или программно-аппаратно, если хотите), либо добавлением аппаратного источника энтропии. Сейчас проблема менее актуальна: в дистрибутивы для платформ, где с получением энтропии трудности, haveged или подобное решение стали включать автоматически.

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



Комментарии (2) »

Процитирую заметку из 2016 года, про MITM для TLS:

Главная проблема с перехватом TLS при помощи MitM в том, что такое решение полностью уничтожает смысл аутентификации узлов на стороне клиента. Дело в том, что клиент больше не может проверять валидность сертификатов оконечного узла, с которым пытается установить соединение: клиент просто не видит этого подлинного узла и сертификатов – он обменивается данными с перехватывающим, подменным узлом и вынужден доверять ему. Если на пути от подменного узла до узла, соединение с которым перехватывается, что-то пошло не так, то обнаружить это “не так” должен перехватывающий узел. Однако, он может этого не делать: вообще, ситуация, когда перехватывающий узел просто не валидирует сертификаты перехватываемого – встречается нередко. Более того, не в интересах перехватывающего прокси заниматься такими проверками. Так, этот узел не может видеть всего контекста установления соединения (часть контекста – у клиента: например, только клиент знает, какие ключи и сертификаты он ожидает получить от сервера), а поэтому в принципе не может надёжно проверить подлинность соединения.

Уточнить, пожалуй, тут можно вот что: во-первых, если перехватывающий узел не проверяет подлинность “внешних” узлов по сертификатам (а нужно считать, что не проверяет), то этот самый узел точно так же может оказаться под атакой MITM, затянув туда и все “внутренние” узлы, которые через него работают; во-вторых, если за MITM-прокси стоит большое количество ничего не подозревающих пользователей, то для третьей стороны повышается привлекательность своего собственного MITM (см. предыдущее предложение) даже с подменными сертификатами от хорошо известного УЦ – просто потому, что такая атака будет направлена на единственный узел (на MITM-прокси) и гораздо больше шансов, что никто не заметит (при этом пользователей, которые попадут под “двойной перехват” – сразу много).



Комментировать »

В этой заметке, в качестве практического примера того, чем может быть полезен открытый исходный код, рассматривается реализация проверки (теоретико-числовых) свойств параметра DH в приложении Telegram, ну или в одной из версий этого приложения – детали тут не важны, а ссылки есть ниже по тексту. (На всякий случай, сразу отмечу – каких-то дефектов, что называется, “выявить не удалось”, да и цели такой не ставилось – это просто достаточно краткий разбор небольшой функции с комментариями из области прикладной криптографии, а не подробный анализ кода.)

DH обозначает протокол Диффи-Хеллмана. В мессенджере Telegram протокол Диффи-Хеллмана используется при создании “секретных чатов”, где он служит для получения общего секрета клиентами (то есть, ключа для зашифрования сообщений). Рассматривается самый простой вариант – обмен сообщениями между двумя пользователями в защищённом режиме.

Telegram использует “классический” (или “мультипликативный”) вариант DH, работающий в мультипликативной группе конечного поля (сейчас такой вариант принято обозначать FFDH – от Finite Field). Если обойтись без строгих научных терминов, то этот вариант DH не “эллиптический” (например), а “обычный”, работающий в арифметике остатков. Про “эллиптический” вариант многие слышали применительно к TLS – там он называется ECDH(E). То, что в Telegram не используется современный вариант на эллиптической кривой – всегда выглядело несколько странно. Скорее всего, этому есть очень простое объяснение, связанное с историей появления протокола MTProto, но, так или иначе, эти детали остаются за рамками данной заметки, которая посвящена свойствам модулей DH и небольшому фрагменту исходного кода приложения, связанному с проверкой этих свойств.

Чтобы определить конкретные параметры протокола DH (FFDH, но не только) – требуется задать достаточно большое простое число. В случае “классического” варианта битовая разрядность этого числа, по современным представлениям, должна быть хотя бы 2048 бит. Telegram требует строго 2048 бит (см. ниже). Данное простое число задаёт базовую структуру для арифметики протокола и называется модулем. От свойств модуля зависит надёжность реализации. Так, слишком маленькая разрядность, – например, 256 бит, – позволяет очень быстро решать обратную задачу (находить дискретный логарифм) и вычислять по открытой информации секретное значение, которым обмениваются стороны. (Дежурное замечание: пример про 256 бит – не относится к разрядности ECDH, там другие алгоритмы и структуры.)

В Telegram, модуль, используемый сторонами, передаётся им сервером. Плохая это практика или хорошая? Для точного ответа информации маловато: с одной стороны, самостоятельное генерирование модуля сторонами может приводить к использованию нестойких модулей (как преднамеренному, так и нет), а кроме того – добавляется вычислительная нагрузка; с другой стороны – использование неопределённого серверного модуля требует доверия серверу или, как минимум, доверия процессу выбора модуля. Так, FFDH всё ещё используется в TLS современной версии 1.3, а значения модулей там, в общем-то, зафиксированы спецификациями, однако для выбора параметров предписан опубликованный процесс. Другими словами: если модуль вам присылает сервер, то, в теории, сервер может прислать заранее тщательно подготовленный модуль, припрятав в рукаве нужные для быстрых вычислений структуры. Telegram присылает модуль с сервера и может присылать разным пользователям и разным “секретным чатам” разные значения модулей, вряд ли за этим кто-то следит. В качестве мер повышения доверия документация (в которой иногда встречаются опечатки) предлагает проводить хорошо известные проверки свойств присланного числа, эти проверки – присутствуют в коде приложения.

Перейдём к особенностям кода. Telegram – среди тех немногих приложений, разработчики которых заявляют так называемую “воспроизводимую сборку“: действительно, публикация исходного кода, сама по себе, не гарантирует, что исполняемое приложение, распространяемое в собранном виде, соответствует опубликованным исходникам. Telegram предлагает описание того, как можно самостоятельно проверить соответствие сборки исходникам. Это хорошо (если работает – я не проверял). Я рассматриваю некоторый исходный код, доступный на GitHub-е по опубликованной ссылке.

Простое число P, представляющее собой модуль DH, поступает с сервера в ответе на запрос getDhConfig, в виде массива байтов. Свойства проверяются в telegram/messenger/SecretChatHelper.java вызовом функции Utilities.isGoodPrime(P, G); (G – это генератор, второй параметр протокола.)

if (!Utilities.isGoodPrime(res.p, res.g)) {
 acceptingChats.remove(encryptedChat.id);
 declineSecretChat(encryptedChat.id, false);
 return;
}

Вся содержательная проверка – внутри isGoodPrime() (telegram/messenger/Utilities.java). Эта функция начинается следующим фрагментом:

if (!(g >= 2 && g <= 7)) {
 return false;
}

if (prime.length != 256 || prime[0] >= 0) {
 return false;
}

BigInteger dhBI = new BigInteger(1, prime);

Первый if проверяет интервал значений генератора.
Следующий if – контролирует разрядность переданного модуля. 256 байтов – это 2048 бит. prime[0] >= 0 – тут проверяется, что старший бит установлен в единицу. Этот оборот может показаться не самым очевидным: тип byte в Java определён со знаком, соответственно, если значение больше либо равно нулю, это означает, что старший бит – нулевой (знак записи числа “плюс”); представление целых чисел большой разрядности (BigInteger – см. следующие строки) здесь использует запись, в которой старший байт – байт с нулевым индексом. Таким образом, prime[0] >= 0 проверяет, что получающееся число будет не меньше, чем 2^2047. new BigInteger(1, prime) – создаёт объект BigInteger и загружает в него значение модуля из массива prime. Единица в левом параметре конструктора – обозначает, что число положительное. Зачем нужен выше фрагмент с if, проверяющий длину и значение старшего бита? Например, сервер мог бы передать 256 байтов, в которых старшие значения были бы нулевыми, тогда длина массива соответствовала бы заданному требованию, но реальная разрядность получившегося в BigInteger числа оказалось бы меньше, так как нулевые байты слева не учитывались бы.

Дальше следует блок (здесь пропущен) из нескольких if..else if, которые, в соответствии со значением генератора, проверяют остатки по простым 3, 5, 7 и некоторым степеням 2. Этот фрагмент, наверное, можно рассмотреть в отдельной заметке из области занимательной математики. Цель проверки – контроль свойств полученного модуля (этим фрагментом вся проверка “доверия серверу” исчерпывается).

А следующая пара строк в telegram/messenger/Utilities.java довольно занимательная (приведено с сокращениями, см. детали ниже):

String hex = bytesToHex(prime);
if(hex.equals("C71CA...")) {
 return true;
}

Полученное с сервера представление модуля (prime) преобразуется в hextext – то есть, в текстовую строку с записью шестнадцатеричными цифрами, – а получившаяся строка сравнивается с константой. Если значение совпало, то модуль считается “хорошим” (обратите внимание, что выше, тем не менее, уже были необходимые проверки по малым простым для того же числа).

Непосредственно в коде зашит вот такой модуль (переносы строк добавлены для удобства – это одно число):

C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F
48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C37
20FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F64
2477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4
A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754
FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4
E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F
0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B

Это простое число (ну, с точностью до детерминированной проверки в SAGE и вероятностной проверки в Mathematica, конечно; но это означает, что простое). То есть, в этом фрагменте – код строго верит в один конкретный модуль. Для других модулей предусмотрена проверка простоты (и статуса safe prime):

BigInteger dhBI2 = dhBI.subtract(BigInteger.valueOf(1)).divide(BigInteger.valueOf(2));
return !(!dhBI.isProbablePrime(30) || !dhBI2.isProbablePrime(30));

Здесь, с помощью вероятностного теста (это единственный способ – известные детерминированные алгоритмы слишком ресурсоёмкие), проверяется, что модуль P простое число и что (P-1)/2 – тоже простое. Обычная практика. На этом проверки заканчиваются (естественно, здесь не может быть никакой аутентификации и тому подобных дополнительных шагов).

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



Комментировать »

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

В общем случае, если исходный код написан хорошо, то, действительно, лучший источник сведений о подробностях работы программы найти весьма трудно (естественно, желательно знакомство с соответствующим языком программирования). Однако с этим вот “общим случаем” связано немало неверных, излишних “обобщений”. Например, верно ли, что “открытый исходный код” позволяет легко находить уязвимости в ПО, а если исходный код скрыт, но предоставляется только исполняемый файл, то уязвимости найти гораздо сложнее? Поэтому, дескать, “закрытое ПО” более безопасно. Проблема тут в том, что такой вопрос подразумевает некорректное сравнение. Дело даже не в том, что некорректно оценивать “безопасность” программного пакета по “степени сложности” чтения исходников (ведь “бинарный исполняемый” код – такой же “исходник”; об этом – ниже). Просто, нет такой метрики, которая позволила бы универсальным способом сравнить “сложность” нахождения уязвимостей в ПО, когда такие уязвимости были найдены разными методами.

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

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

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

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



Комментировать »