6.3. Что нужно знать программисту | Телекоммуникации вчера, сегодня, завтра

Последовательность действий при создании объекта радиосвязи

Бланк формы №1 ТАКТИКО-ТЕХНИЧЕСКИЕ ДАННЫЕ РЭС

Поставка оборудования обеспеченного радиочастотами

Витрина



6.3. Что нужно знать программисту

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

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

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

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

Теперь рассмотрим основные свойства базовых криптографических примитивов.

6.3.1. Блочные шифры

Блочные алгоритмы шифрования применяются, пожалуй, чаще, чем любые другие шифры. Блочный шифр выполняет операции над блоками — порциями данных фиксированного размера.  Обычно размер блока составляет 64 бита (8 байт) или 128 бит (16 байт), но некоторые алгоритмы используют и другие значения. Блочный шифр всегда преобразует определенный блок открытого текста в один и тот же шифртекст независимо от того, какие данные были зашифрованы до этого.

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

Если алгоритм оперирует 8-байтовыми блоками данных, а в последнем блоке, например, только 3 байта полезных данных, то все неиспользуемые байты, кроме самого последнего, можно заполнить любым значением, а в последнем байте записать число, равное количеству неиспользуемых байтов. Тогда, получив и расшифровав все блоки, необходимо отбросить с конца столько байт, сколько указано в последнем байте последнего блока. Правда, если исходное сообщение имело длину, кратную размеру блока, то возникает некоторая сложность, т. к. требуется добавить 0 байт, и последний байт должен содержать число байт дополнения. Для разрешения этой проблемы при зашифровании добавляется новый блок, последний байт которого содержит размер блока. Дополнительный блок будет целиком отброшен при расшифровании.

Блочные алгоритмы шифрования могут быть использованы в нескольких режимах, например:

  • режим простой замены (Electronic CodeBook, EC В);
  • с зацеплением блоков шифртекста (Cipher Block Chaining, С ВС);
  • с обратной связью по шифртексту (Cipher FeedBack, CFB);
  • с обратной связью по выходу (Output FeedBack, OFB);
  • по счетчику (Counter);
  • с зацеплением блоков открытого текста (Plaintext Block Chaining, PBC);
  • с обратной связью по открытому тексту (Plaintext FeedBack, PFB);
  • с усиленным сцеплением блоков шифртекста (различные модификации режима СВС);
  • с обратной связью по выходу и нелинейной функцией (Output FeedBack with Nonlinear Function, OFBNLF);
  • по счетчику с нелинейной функцией  (Counter with Nonlinear Function, CNLF).

Этот список далеко не полный и может быть расширен чуть ли не до бесконечности.

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

6.3.2. Потоковые шифры

Потоковый шифр выполняет операции над битами или символами (например, 8-, 16- или 32-битовыми). Потоковый шифр преобразует один и тот же символ открытого текста в разные символы шифртекста, например, в зависимости от того, сколько и каких символов было обработано ранее.

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

Таким образом, стойкость алгоритма зависит исключительно от характеристик гаммы, выдаваемой генератором. Если гамма состоит из одних нулей (вырожденный случай), то данные при шифровании вообще не изменяются. Если гамма имеет короткий период (например 32 бита), то шифрование сводится к операции XOR С 32-битовой константой. Если же гамма представляет собой случайный набор битов, не подчиняющийся никакой закономерности, получается аналог одноразового шифровального блокнота, который обеспечивает абсолютную защиту. Разумеется, детерминированный алгоритм, используемый в генераторе гаммы, не может выдавать истинно случайную последовательность. Если последовательность не удастся повторить, то не удастся и расшифровать сообщение.

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

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

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

Более детальное описание достоинств и недостатков потоковых шифров также можно найти в специализированной литературе по криптографии.

6.3.3. Алгоритмы с открытым ключом

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

Стойкие алгоритмы с открытым ключом, как правило, основываются на математических задачах, которые на настоящий момент не имеют эффективного решения. Однако далеко не все стойкие алгоритмы применяются на практике. Некоторые из них требуют очень больших ключей. Например, размер открытого ключа криптосистемы HFE (Hidden Fields Equations) может достигать десятков мегабайт, что затрудняет распределение таких ключей. При использовании некоторых алгоритмов размер шифртекста значительно превышает размер соответствующего ему открытого текста. Не последнюю роль играет и скорость выполнения шифрования — все асимметричные алгоритмы значительно медленнее, чем симметричные.

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

Общей проблемой алгоритмов с открытым ключом является необходимость распространения этих самых открытых ключей. Используя асимметричную криптографию, можно вести защищенный диалог с абонентом, с которым был совершен обмен открытыми ключами. Но в обшем случае, не проводя подготовительных действий и не имея общего секрета, невозможно с уверенностью утверждать, что абонент является именно тем, за кого он себя выдает. Для решения этой проблемы используется инфраструктура открытых ключей (Public Key Infrastructure, PKI), которая при помощи иерархии сертификатов позволяет свести доверие абоненту к доверию корневому сертифицирующему центру.

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

6.3.4. Хэш-функции

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

Похожие требования предъявляются к функциям вычисления контрольных сумм (Cyclical Redundancy Check, CRC), таким как CRC32 или Adler32. Но контрольные суммы призваны, в первую очередь, обнаруживать случайные нарушения целостности. Так что задача подбора двух сообщений, контрольные суммы для которых будут совпадать, или нахождения сообщения с заданным значением контрольной суммы может быть решена эффективно. Например, достаточно откорректировать всего 4 идущих подряд байта, расположенных в любом месте изменяемого сообщения, чтобы значение CRC32 для этого сообщения осталось таким же, как до внесения изменений. Поэтому контрольные суммы (обычно очень простые в реализации) не стоит использовать в криптографии.

Если на выходе хэш-функции, реализующей идеальное, случайное равновероятное отображение, получается, например, 128-битовое значение и хэш-функция была вычислена от 2128 разных сообщений, это не значит, что каждое из 2'28 возможных выходных значений получилось ровно один раз. Действительно, предположим, что мы вычислили хэш ровно от половины (2т) входных сообщений, и получили 21" разных выходных значений, т. е. не было ни одного повторения. Учитывая тот факт, что отображение случайно и равновероятно значение хэш-функции от следующего сообщения с вероятностью '/2 будет совпадать с одним из уже полученных значений. И с каждым новым значением хэша вероятность возникновения коллизии будет только возрастать.

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

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

6.3.5. Генераторы случайных чисел

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

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

Первый недостаток заключается в том, что невозможно точно сказать, сколько бит действительно случайных данных может быть получено из одной пары нажатий или одного движения мышью. У людей с профессиональными навыками машинописи, как правило, очень высокая ритмичность нажатия клавиш. А случайные данные должны получаться независимо от того, кто сидит за клавиатурой. Да и щелчки при нажатии кнопок могут быть легко записаны злоумышленником на магнитофон, а потом воспроизведены для повторения задержек. С мышью тоже не все понятно — данные, которые получает программа, проходят много инстанций. Мышь передает информацию о перемещении с определенной периодичностью, а не в тот момент, когда датчик перемещения получает информацию о том, что мышь была сдвинута. А драйвер мыши извещает программу о состоянии мыши со своей дискретностью. Все это приводит к тому, что программа получает далеко не полную информацию о том, что произошло с мышью, и основная часть случайных данных, на которые рассчитывала программа, может при определенной комбинации мыши, драйвера и компьютера оказаться совсем не случайной.

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

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

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

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

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

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

6.3.6. Криптографические протоколы

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



Поиск по сайту


Смотрите также