Ч. 1. Гл. 4. Запасы по прочности ПО. Криптография

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

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

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

Например, ГОСТ 28147-89 (который потом поименовали "Магма" в более новом ГОСТ Р 34.12-2015) оказался недостаточно стойким с некоторых позиций. Однако его "запас прочности" был достаточно высок. Уровень защиты в 128 битов - это хороший уровень. Но у "Магмы" был в два раза больше, поэтому даже снижение уровня криптографической защиты в результате некоторой нестойкости алгоритма не повлекло за собой возможности серьёзного практического снижения его криптостойкости.
Снижение криптостойкости произошло лишь в случае, когда алгоритм "Магма" использовался совместно с непредназначенной для этого схемой XTS в VeraCrypt. Там оказалось, что XTS была разработана для AES с блоком 128 битов, а у "Магмы" битов всего 64 в блоке. Здесь мы видим, кстати, что не хватило другого количественного показателя, вроде бы, не относящегося к делу. Но не хватило. Не так уж он и не относился к делу, как казалось поначалу.

Да, квантовые компьютеры обещают снижение криптостойкости алгоритмов примерно в 2 раза, возможно, даже в 3 раза. Таким образом, при большом желании, ГОСТ можно будет расшифровывать, однако по сравнению с AES в конфигурации с длиной ключа 128 битов ГОСТ всё равно более стойкий, несмотря на то, что более старый. В нём таких малых длин ключей просто не предусмотрено. Возможно, кстати, и зря не предусмотрено, потому что часть данных нужно шифровать буквально на несколько дней или лет и требования к стойкости там значительно ниже, так как ничего принципиально нового не появится за время существования шифротекста.

Ещё один возможный пример. Некоторое время TLS 1.0 имел известные атаки на все стандартые наборы шифров. Потому что атаки могли производится на саму схему шифрования CBC, а единственный шифр не по этой схеме - это RC4, который примерно в то же время сломали практически окончательно.

Однако, если бы мы использовали сразу два шифра вместо одного, то всё было бы по-другому. Использование шифра RC4 поверх любого стойкого CBC-шифра повысило бы стойкость шифрования и не дало бы на практике проводить атаки. Разумеется, при использовании двух разных независимых друг от друга ключей (или зависимых, но криптостойко).

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

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

Далее. Атака на шифр RC4, насколько я помню (атака Ванхофа и Писсенса), включала в себя многократное шифрование одним и тем же ключом с разными синхропосылками (открытыми векторами инициализации) одних и тех же данных (тех же заголовков HTTP-запросов). Затем вычисляется статистика, по которой можно установить ключ шифрования. Однако, при широфвании в режиме CBC с разными синхропосылками, мы бы увидели очень простую штуку: CBC рандомизирует результаты для RC4, не позволяя накопить соответствующую статистику.
Разумеется, это не означает, что такую схему можно использовать после того, как хотя бы один из двух алгоритмов стал уязвимым. Однако, такая схема имела запас по прочности. Если бы в TLS 1.0 присутствовала бы такая схема, то пользователи TLS 1.0 могли бы использовать её для защиты своих соединений и повышать их стойкость до тех пор, пока проблема не была бы устранена. На практике же, некоторое время пользователи вынуждены были использовать либо уязвимый RC4, либо уязвимый CBC. Даже спустя лет пять, человек, полностью имеющий доступ к интернет-каналу, может заставить деградировать протокол TLS 1.2 до TLS 1.0, если это разрешено на клиенте, и заставить клиента использовать уязвимые алгоритмы.
То есть и здесь "удвоение толщины" могло бы послужить хорошую службу в деле повышения стойкости.

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

Использование максимально возможных длин ключей также усиливает алгоритмы и против квантовых компьютеров. Кстати, это не относится к использованию более стойких алгоритмов шифрования. Так, мы видим, что пользователь эллиптических кривых более уязвим к квантовым компьютерам, чем пользователь RSA. Почему?
Потому что все эти алгоритмы будут, видимо, сломаны квантовыми компьютерами сразу же при их появлении. Однако, для эллиптических кривых, компьютер должен иметь объём примерно от 256 до 512 кубитов, в то время, как для RSA объём должен быть от 4096 до 16384 кубитов (при сравнимой с эллиптическими кривыми стойкости) в зависимости от размера ключа. То есть компьютеры с большим количеством кубитов появятся позже, а значит, RSA простоит реально на несколько лет дольше. Забавно, ведь эллиптические кривые, вроде как, более совершенны.
Когда я изучал эллиптические кривые, я думал: вот, RSA совершенно бесмыссленен. Если к эллиптическим кривым нужно каждый год прибавлять по биту, чтобы компенсировать рост вычислительной мощности компьютеров, то к RSA каждый год нужно прибавлять всё больше и больше битов, чем больше будет мощность. Путь в никуда, ведь для среднего компьютера с каждым годом (каждым битом ключа и увеличением мощности компьютера) расшифрование всё проще, а зашифрование всё сложнее. Однако, оказалось, что это свойство неожиданно стало достоинством, хоть и временным.
Кроме этого, RSA менее чувствительны к не совсем случайной генерации ключа, так как даже если в алгоритме генерации есть неслучайности, для 4096-битного ключа достаточно, чтобы каждый 8-ой бит был случайным для обеспечения случайности на уровне 256-ти битов. То есть он прощает больше ошибок.

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

К сожалению, очень часто криптографические библиотеки и алгоритмы делаются без запасов по длине ключа. Поэтому использовать, скажем, 1024-ёх битный ключ симметричного шифрования не получится: таких стандартных алгоритмов просто нет. Однако, по крайней мере, стоит использовать наиболее надёжные и длинные алгоритмы, если это позволяют обстоятельства.
Конечно, всё стоит денег. Увеличение длин ключей и количества используемых алгоритмов всегда приводит к минусам:
1. Эти алгоритмы надо верно запрограммировать
2. Ключи нужно сгенерировать, и обязательно сгенерировать в достаточной степени независимымми друг от друга
3. Вычислительная трудоёмкость значительно выше, из-за чего имеем сразу два минуса:
3.1. На клиенте быстрее разряжаются батареи, если клиент работает от батарей.
3.2. На сервере нужны более мощные системы. Особенно актуально, если криптография подвергается DOS-атаке (атаке на отказ в обслуживании).

Таким образом, мы видим, что в криптографии "запасы по прочности" можно даже делать числовыми. Кстати, напомню, что в лифтах запасы по прочности в 10 раз вполне обычны. В скоростных лифтах на тросы запасы могут быть и в 16-ть раз. Во многих конструкциях, от которых зависят жизни людей, запасами в несколько раз никого не удивишь. И никто не говорит об экономии, потому что всем надоело думать, когда грохнется очередной самолёт, потому что мы сделали его слишком дешёвым.

Так что запас по длине всего в 2-4 раза - это не так много. Всегда лучше использовать максимально возможную длинну ключа из доступных и наиболее стойкие алгоритмы из доступных. Зачастую, наиболее известные и стандартные алгоритмы привлекают больше внимания криптоаналитиков, поэтому они могут считаться более проверенными и стойкими.