Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Практическая криптография алгоритмы и их программирование

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
Глава 4. Как устроены современные шифры 81
возможно представить в виде суммы произведений некоторых постоянных коэф-
.
, x1, ..., xn:
0
фициентов со слагаемыми аргументами ни для какого из наборов x
( , , ,..., ) ...
Fx x x x a x ax a x
012 00 11
=+++
nnn
Почему это плохо? Простое линейное преобразование, которое возможно дало бы нужный результат, не может быть использовано по той причине, что в этом случае криптоаналитик просто вычислит его с помощью статистического оценивания, используя, например, метод нахождения линейной регрессии, и най­дет формулы всех использованных линейных преобразований данных.
16
Если все же используем такую функцию F, которая обладает указанным свойством, то есть является линейной, мы можем представить себе следующую ситуацию. Имея пары {участок открытого текста} и {соответствующий ему закры­тый текст}, криптоаналитик сможет составить алгебраическую систему вида (*) и решить ее, найдя все необходимые ему компоненты для вскрытия шифра ка­ким-нибудь не очень сложным и не очень медленным методом решения систем ли­нейных алгебраических уравнений, которые в вузах изучают студенты начальных курсов.
1
i
В (*) функции
представляют собой i-е по счету линейное преобразование,
f
k
зависящее от ключа kP
fP C
fP C
(*)
...,
 
fP C
è Cnпредставляют собой участки (биты, байты или би-
n
=
() ,
k
11
2
=
() ,
22
k
=
() .
knnn
товые строки) соответственно открытого и шифротекста. На многие современные блочные шифры были реализованы подобные атаки. Дополнительный анализ ино­гда приводит еще и к тому, что удается найти функции зависимости не только для конкретных пар открытого и шифротекста, но и для устройства непосредственно шифра, что вдобавок позволяет все найденные функции отделить друг от друга. То есть создать модель шифра, в которой четко прослеживались последствия из­менения бита исходного текста всего на двух-трех битах выхода.
Шифр Люцифер строился под руководством Файстеля в конце 60-х годов с учетом подобных возможностей и сообразительности криптоаналитика. Позже эти работы стали финансироваться Национальным институтом стандартов и тех­нологий США (National Institute of Standards and Technology), поскольку их резу­льтатом должно было стать формирование нового национального стандарта шиф­рования, позволившего бы шифровать данные для создания защищенных каналов передачи данных.
16
Здесь нужно четко представлять себе тонкое различие между открытостью алгоритма в соответствии правилами Керкхоффа и закрытостью алгоритма, измененного на время шифрова ния с помощью ключа. Функция F, о которой идет речь в данном конкретном случае, уже изме нена в зависимости от заданного пользователем ключа и скрыта от глаз криптоаналитика. Поэ тому поиск формулы, преставляющей функцию F, то же самое, что и поиск ключа, только в ме нее очевидном виде.
-
-
-
-
82 Глава 4. Как устроены современные шифры
Файстель в своей статье представил способ организации шифра по Шеннону. Этот шифр обладал хорошими свойствами перемешивания и рассеивания. Для до­стижения вышеозначенного эффекта предлагалось использовать блоки подстано­вок и перестановок. Архитектура подобных шифров носит название SP-ñåòè,от двух названий используемых в ней компонентов: S-box è P-box.
Данные представлялись в виде подблоков небольшого размера, например, в 3 или 4 бита. Затем использовалась заранее подготовленная таблица подстановки (например, рис. 4.4), названная Файстелем S-Box (от substitution — в английском языке обозначающего подстановку или замену) и окрещенная в русской термино­логии S-блоком и узлом (иногда еще говорят, блоком) замены.
x1x2x3x
00001101 00011011 00100100 00110101 01000000 01011001 01101010 01110111 10000010 10010011 10100001 10110110 11001110 11011100 11101000 11111111
Ðèñ. 4.4. Пример таблицы замен для n = 4
4
S(x)
Подставляя значение входных данных в левую колонку таблицы, получаем соответствующее значение подстановки в правой колонке. Как в левой, так и в правой колонках все значения должны быть различны, иначе, заменив однажды данные в соответствии с таблицей, мы не сможем однозначно их восстановить позже.
В варианте для компьютерного исполнения небольшая таблица замен обычно организуется как обычный массив (см. листинг 4.5).
Листинг 4.5
int S_Box[16] = {
13, 11, 4, 5, 0, 9, 10, 7, 2, 3, 1, 6, 14, 15, 12, 8 }
Глава 4. Как устроены современные шифры 83
for(inti=0;i<size_of_data; i++) {
int data_l, data_h;
data_l = (data[i] >> 4) & 0xF; // берем младший полубайт // его размер как раз равен 4 битам data_l = S_Box[data_l];
data_h = data[i] & 0xF; // берем старший полубайт // и поступаем с ним та кже, как с младшим data_h = S_Box[data_h];
data[i] = data_h || (data_l << 4); // возвращаем половинки назад }
Читатель, ознакомившийся со второй главой книги, возможно, сразу предло­жит способ взлома шифра, использующего таблицу замен, — это простой частот­ный анализ. В роли букв латинского алфавита из классических примеров здесь выступят всевозможные двоичные последовательности — комбинации из четы­рех битов. Чтобы сделать схему с таблицей замен стойкой к анализу, требуется значительно увеличить размер обрабатываемых двоичных последовательностей, чтобы во много раз усложнить частотный анализ. Для этого надо будет использо­вать например 128-битовую таблицу замен, а следовательно, хранить все 128 зна­чений 128-битовых векторов. Для этого понадобится 16 kb памяти только для од­ной таблицы. Кроме того, возникает вопрос об использовании такой таблицы в ка­честве ключа — она все-таки слишком громоздка. Это означает, что необходимо придумать способ расширить небольшой по размеру ключ до необходимого разме­ра и модифицировать постоянную таблицу в соответствии с ним. В силу явных трудностей с реализацией метода сотрудники Bell Laboratories обратили внима­ние еще и на таблицы перестановок (рис. 4.5).
Ðèñ. 4.5. Пример таблицы перестановок для n = 8
84 Глава 4. Как устроены современные шифры
Таблица перестановок была названа P-Box (от permutation — перемешива­ние) или узел (блок) перестановки по аналогии с узлом (блоком) замены. С ее по­мощью в блоке данных биты переставляются так, чтобы затруднить частотный анализ. При этом даже для сравнительно небольших блоков мы получаем очень большое пространство возможных ключей, равное по мощности N! Например, для 16-битового блока 16! = 20922789888000). Впечатляющее число, не правда ли?
Однако для блока перестановки легко придумать криптографическую атаку, которая позволит быстро (всего за N1 операций, если блок перестановки состо­ит из N элементов) раскрыть структуру его содержимого. Немного присмотрев­шись к рис. 4.5, читатель может увидеть, что для этого достаточно подать на вход строки битов, содержащие одну единицу и остальные нули: то есть последова­тельность
(1, 0, 0, 0, ..., 0, 0),
(0, 1, 0, 0, ..., 0, 0),
(0, 0, 1, 0, ..., 0, 0),
(0, 0, 0, 1, ..., 0, 0) èò.ä.
После этого единица на выходе будет соответствовать тому элементу, на мес­то которого переставляется исходный единичный бит.
Если криптоаналитик получит доступ к шифровальной машине (или програм­ме), то, просто подставив все векторы, легко получит формулу преобразования данных и сможет раскрывать все тексты, зашифрованные с ее помощью.
Таким образом, у нас есть два различных способа преобразования данных, каждый из которых уязвим к определенному виду криптоатак. При этом мы зна­ем, что с точки зрения формального подхода наиболее эффективным шифром из всех возможных блочных шифров является тот, который может преобразовать любой возможный блок открытого текста в любой возможный блок шифрованно­го текста. И естественно, это преобразование должно быть обратимым. Такой шифр можно отнести к шифрам на основе простой подстановки, который в упро­щенном варианте был описан S-блоком.
Теперь вернемся к реальности и проведем простой расчет. Если блок шифра имеет длину n битов, то имеется 2
n
различных двоичных блоков и (2n)! способов, с помощью которых можно зашифровать один блок текста. Количество битов клю­ча, необходимых для выбора одного из этих способов, огромно — оно равно
{2n)!}. Это неприемлемо большое число даже при небольших значениях n.Íà-
log
2
пример, при n, равным 8, нам потребуется хранить ключ длиной почти в 2000 би­тов. Плюс ко всему простые подстановки на малых алфавитах можно эффективно раскрывать посредством составления частотных таблиц для знаков шифрованно­го текста. Мы оказываемся перед дилеммой — нам нужны блоки больших разме­ров, но мы не сможем эффективно их использовать из-за слишком большой длины ключа.
Разрешить ее можно, пойдя по стопам сотрудников лаборатории IBM. Почти все первые криптосистемы IBM базируются на работе Шеннона и его композици­онных шифрах. Для построения сильной системы из слабых по отдельности ком
-
Глава 4. Как устроены современные шифры 85
понент используется произведение шифров, а точнее, их многократное последова­тельное применение над данными. Понятно, что последовательное применение, например, двух блоков замены равносильно применению одного третьего блока замены. Поэтому применение замен и перестановок необходимо чередовать меж­ду собой. Именно так и поступили в IBM.
Несмотря на незначительные различия в реализациях, почти во всех систе­мах фирмы IBM в основном использовалась перестановка внутри блока для неко­торого фиксированного перемешивающего преобразования и подстановка для 4-битовых подблоков (рис. 4.6). Кстати, название «узел замены» появилось имен­но отсюда, поскольку оно наглядно демонстрирует позицию блока замены в архи­тектуре шифра как некоторую узловую операцию, в которой своего рода узлом сходятся линии, обозначающие поступление данных.
Файстелем была описана такая схема в качестве примера эффективной крип­тосистемы. В ней блок из 128 битов открытого текста разбивается на 32 4-битных подблока, каждый из которых подвергается действию различных S-блоков, кото­рые управляются частью заданного пользователем ключа. Затем полученные 128 битов перемешиваются с помощью фиксированной перестановки, и процесс по­вторяется. Перестановка перемешивает биты различных S-блоков и необходима для того, чтобы предотвратить вырождение всего преобразования в подстановку 4-битовых блоков. Расшифрование происходит аналогично, за исключением того, что в качестве S-блоков используются их обратные подстановки.
К сожалению, в данной схеме есть существенные недостатки. Дело в том, что в данном случае S-блоки являются секретной частью алгоритма шифрования. Все они должны быть различными, следовательно, для их хранения понадобится це-
ëûõ (4!)
128
= 768 битов.
4
Ðèñ. 4.6. Композиционный шифр из перестановок и подстановок
86 Глава 4. Как устроены современные шифры
Чтобы преодолеть данные трудности, Файстель использовал только два раз­личных S-блока (S0 и S1), структура которых известна вместе с алгоритмом. Тог­да каждый из S-блоков на рис. 4.6 будет заменен либо S0, либо S1, в зависимости от значения одного бита ключа. Это снижает требования к памяти для S-блоков до 128 битов и к длине ключа до 512 битов. Дальнейшее уменьшение размера ключа до 128 битов было достигнуто за счет использования алгоритма разворачи­вания ключа (key shedule), который просто повторяет каждый бит ключа четыре раза.
Каждый 4-битовый S-блок можно реализовать в виде массива в памяти объе­мом в шестнадцать 4-битовых слов. Поскольку S-блок должен быть обратимым, все слова должны быть разными. Следовательно, простейшая реализация одного 4-битового S-блока потребует от нас наличия 64 битов памяти, для 8-битового S-блока потребуется уже 2048 битов памяти, а 16-битовый S-блок «отъест» при­личный кусок в один мегабайт. В IBM выбрала размер в 4 бита, выдержав своего рода компромисс между стоимостью и надежностью.
Если бы был выбран 2-битовый вариант, то вся система могла быть раскрыта за несколько секунд работ персонального компьютера. Это произошло бы потому, что все 4! = 24 обратимых отображения 2 битов в 2 бита являются линейными (или, если быть точным — аффинными) и могут быть представлены в виде линей­ного уравнения, в котором вся арифметика выполняется по модулю 2. Факт того, что перестановка является линейной операцией, а композиция аффинных отобра­жений дает аффинное отображение, показывает, что использование S-блоков в этом случае было бы равносильно одному линейному преобразованию. В этом случае, даже не пытаясь найти ключ, можно было бы получить открытый текст из решения системы линейных уравнений методом, описанным в начале раздела.
Следовательно, при создании S-блоков аффинных отображений следует избе­гать. Отображений, «близких» к аффинным, тоже следует избегать, что, по-види­мому, и отразилось в решении не использовать 3-битовые узлы замены, хотя в данном случае аффинными будут всего лишь 3% обратимых отображений 3 битов в 3 бита. Вместо этого были созданы и использованы 4-битовые S-блоки.
Криптосистема Lucifer
However, this does not mean that the LUCIFER algorithm is useless. If a reasonably good stream cipher is used both before and after LUCIFER, its weaknesses essentially become irrele­vant, and its strengths are still present. It might indeed be ar­gued that this kind of precaution ought to be used with DES as well.
J. Savard. A Cryptographic Compendium
Шифр Люцифер стал логическим продолжением начатого исследования по созданию алгоритма криптографического преобразования данных. В отличие от предложенного ранее способа шифрования, реализованного в лабораториях IBM впервые, Люцифер организован уже в соответствии с принципами сети Файстеля.
Глава 4. Как устроены современные шифры 87
Однако он унаследовал наработанные принципы создания и использования бло­ков подстановки и перемешивания.
Свои изобретения Файстель защитил с помощью нескольких патентов, клю­чевым из которых стал «Способ блочного криптографического преобразова­ния» — он же Люцифер, одобренный патентной комиссией в 1974 году. Алгоритм работы Люцифера был отображен также в одной из статей в «Журнале криптоло­гии», однако настоящая его реализация была несколько сложнее, чем приведен­ная в опубликованной статье.
Шифр изначально имел размер блока шифрования, равный 128 битам. Такого же размера использовался и ключ к шифру. Функция зашифрования своей струк­турой точь-в-точь повторяет описанную разделом выше сбалансированную сеть Файстеля.
Процедура зашифрования состоит из шестнадцати последовательно выпол­няемых над блоком данных раундов, в каждом из которых результат выполнения функции гаммирования F от левой половины блока входных данных складывает­ся по модулю 2 с правой половиной блока. После выполнения каждого раунда ле­вая и правая половины меняются местами, в соответствии с принципом сети Файстеля.
Понятно, что выполнять обмен половинок после выполнения последнего ра­унда бессмысленно — это лишняя операция, которая не модифицирует данные существенным образом, никак не затрудняя криптоанализ, и в то же время бу­дет явно замедлять процесс зашифрования данных очень больших объемов. Поэ­тому обычно обмен полублоков после последнего раунда можно опустить как излишний.
Каждый раунд шифра использует свой уникальный ключ раунда, представ­ленный 72-битовым подключом. Данный подключ для первого раунда состоит из первого байта основного ключа, который просто повторяется дважды (почему это так, станет ясно чуть позже), а затем дополняется следующими 7 байтами ключа (ведь 72-битный ключ раунда состоит ровно из 9 байтов). Подключ для каждого следующего раунда получается циклическим сдвигом ключа предыдущей итера­ции шифра влево на 7 байтов (56 битов).
Понятно, что критической частью алгоритма является функция гаммирова­ния, на которую возлагается задача генерации блока гаммы с как можно более случайным поведением. Роль функции F в алгоритме играет следующая конст­рукция:
1. Правая половина блока складывается по модулю 2 с последними 8 байтами
подключа.
2. Полученный результат преобразуется в зависимости от ключа. В соответ­ствии с первым байтом подключа раунда меняются местами полубайты получив­шейся гаммы. Если соответствующий бит ключа равен 1, обмен происходит, ина­че байт остается неизменным.
3. Затем с помощью двух блоков замены меняется весь 8-байтовый блок гам­мы. Для старших полубайтов используется узел замены S0, для младших — S1. Таким образом, их влияние на гамму косвенно зависит от ключа. Значения S-бло­ков приведены на рис. 4.7.
88 Глава 4. Как устроены современные шифры
4. После этого 64 бита результата перемешиваются с помощью таблицы пере­становки, заданной от младшего бита к старшему (рис. 4.8).
x1x2x3x
000011000111 000111110010 001001111110 001110101001 010011100011 010111011010 011010110000 011100000100 100000101100 100101101101 101000110001 101100011010 110010010110 110101001111 111001011000 111110000101
Ðèñ. 4.7. Узлы замены шифра Люцифер
4
S0(x) S1(x)
Áèò Номер результирующего бита для перестановки Áèò
0 16 32 48
10 21 52 56 27 1 47 38 18 29 60 0 35 9 55 46
26 37 4 8 43 17 63 54 34 45 12 16 51 25 7 62
42 53 20 24 59 33 15 6 50 61 28 32 3 41 23 14
58 5 36 40 11 49 31 22 2 13 44 48 19 57 39 30
Ðèñ. 4.8. Блок фиксированной перестановки шифра Люцифер
15 31 47 63
К сожалению, несмотря на то что шифр Люцифер обладает довольно боль­шим размером блока и достаточной длины ключом, он оказался весьма уязвим к криптографическим атакам. Это действительно имеет место в силу двух причин, одна из которых заключается в слабости алгоритма разворачивания ключа, а вто­рая находится в слабых узлах замены.
Попробуем реализовать на практике предложенный шифр. Как использовать таблицы замен уже было показано в одном из предыдущих листингов. Осталось запрограммировать таблицу перестановки и использовать остов шифра с архитек­турой сети Файстеля. Результат должен быть приблизительно похож на демонст­рируемый в листинге 4.6.
Глава 4. Как устроены современные шифры 89
Листинг 4.6
#include <stdio.h> #include <mem.h>
// узлы замен uint8_t S0_box = {
12, 15, 7, 10, 14, 13, 11, 0,
2, 6, 3, 1, 9, 4, 5, 8
}
uint8_t S1_box[16] = {
7, 2, 14, 9, 3, 11, 0, 4,
12, 13, 1, 10, 6, 15, 8, 5
}
// блок перестановки uint8_t P_box[64] = {
10, 21, 52, 56, 27, 1, 47, 38, 18, 29, 60, 0, 35, 9, 55, 46, 26, 37, 4, 8, 43, 17, 63, 54, 34, 45, 12, 16, 51, 25, 7, 62, 42, 53, 20, 24, 59, 33, 15, 6, 50, 61, 28, 32, 3, 41, 23, 14, 58, 5, 36, 40, 11, 49, 31, 22, 2, 13, 44, 48, 19, 57, 39, 30
}
#define NUM_OF_ROUNDS 16
// data = указатель на 128-битовый блок открытого текста // key = 128-битный ключ void enc_Lucifer(uint8_t *data, uint8_t *key) {
int i, b, j; uint8_t subkey[16][9]; // 72-битовые подключи uint8_t *swap, p[8]; uint8_t *left = data, *right = data+8; // технический прием, // позволяющий избежать лишних операций копирования данных
// ---------------------------------------------­// разворачиваем 128-битовый ключ // первый байт основного ключа повторяется дважды subkey[0][0] = key[0]; subkey[0][1] = key[0]; // затем подключ дополняется остальными байтами ключа for (i = 2; i < 16; i++) subkey[0][2] = key[1]; // генерируем остальные подключи циклическим сдвигом на 7 байтов for (i = 1; i < 16; i++) {
subkey[i][0] = subkey[i-1][2]; subkey[i][1] = subkey[i-1][3]; subkey[i][2] = subkey[i-1][4]; subkey[i][3] = subkey[i-1][5]; subkey[i][4] = subkey[i-1][6]; subkey[i][5] = subkey[i-1][7]; subkey[i][6] = subkey[i-1][8]; subkey[i][7] = subkey[i-1][0]; subkey[i][8] = subkey[i-1][1];
}
90 Глава 4. Как устроены современные шифры
// ---------------------------------------------­// циклы шифрования for (i = 0; i < NUM_OF_ROUNDS; i++) {
// вычисляем гамму: правая половина блока складывается //помодулю2споследними восемью байтами подключа subkey[i][1] ^= right[0]; subkey[i][2] ^= right[1]; subkey[i][3] ^= right[2]; subkey[i][4] ^= right[3]; subkey[i][5] ^= right[4]; subkey[i][6] ^= right[5]; subkey[i][7] ^= right[6]; subkey[i][8] ^= right[7];
// в соответствии с первым байтом подключа // меняем местами полубайты получившейся гаммы for(b=0;b<8;b++)
// если соответствующий бит ключа равен 1 if ((subkey[i][0] >> b)&1!=0){
// меняем местами старший и младший полубайты subkey[i][b+1] =
(subkey[i][b+1] << 4) | (subkey[i][b+1] >> 4);
}
// с помощью двух блоков замены меняем весь блок гаммы for(b=1;b<9;b++) {
subkey[i][b] = (S0_box[subkey[i][b] >> 4] << 4) |
(S1_box[subkey[i][b] & 0xF];
}
// переставляем биты в p memset(p, 0, 8); for(j=0;j<8;j++) {
for(b=0;b<8;b++) {
s = P_box[j*8 + b]; p[s / 8] ^= ((subkey[i][j] >> b) & 1) << (s % 8);
}
}
// в соответствии с принципом сети Файстеля // левая половина блока ксорится с гаммой for(b=0;b<8;b++) left[b] ^= p[b];
// очень быстро меняем местами половинки swap = right; right = left; left = swap;
}
}
Приглядевшись к алгоритму, сразу становится ясно, зачем в каждом подклю­че был продублирован первый байт исходного ключа в самом начале алгоритма. В самом алгоритме шифрования в каждом цикле левая половина блока складыва­ется со значением старших восьми байтов подключа. Вместо того чтобы заводить
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]