Разработка проекта автоматизации обработки звонков и сообщений

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

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 13.10.2013
Размер файла 6,1 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Шифрование -- способ преобразования открытой информации в закрытую и обратно. Применяется для хранения важной информации в ненадёжных источниках или передачи её по незащищённым каналам связи. Согласно ГОСТ 28147-89, шифрование подразделяется на процесс зашифровывания и расшифровывания.

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

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

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

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

Достоинства симметричного шифрования:

- скорость (по данным Applied Cryptography -- на 3 порядка выше);

- простота реализации (за счёт более простых операций);

- меньшая требуемая длина ключа для сопоставимой стойкости;

- изученность (за счёт большего возраста).

Недостатки:

- сложность управления ключами в большой сети. Означает квадратичное возрастание числа пар ключей, которые надо генерировать, передавать, хранить и уничтожать в сети. Для сети в 10 абонентов требуется 45 ключей, для 100 уже 4950, для 1000 -- 499500 и т. д.;

- сложность обмена ключами. Для применения необходимо решить проблему надёжной передачи ключей каждому абоненту, так как нужен секретный канал для передачи каждого ключа обеим сторонам.

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

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

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

В настоящее время симметричные шифры -- это:

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

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

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

Типичным способом построения алгоритмов симметричного шифрования является сеть Фейстеля. Алгоритм строит схему шифрования на основе функции F(D, K), где D -- порция данных, размером вдвое меньше блока шифрования, а K -- «ключ прохода» для данного прохода. От функции не требуется обратимость -- обратная ей функция может быть неизвестна. Достоинства сети Фейстеля -- почти полное совпадение дешифровки с шифрованием (единственное отличие -- обратный порядок «ключей прохода» в расписании), что сильно облегчает аппаратную реализацию.

Операция перестановки перемешивает биты сообщения по некоему закону. В аппаратных реализациях она тривиально реализуется как перепутывание проводников. Именно операции перестановки дают возможность достижения «эффекта лавины». Операция перестановки линейна -- f(a) xor f(b) == f(a xor b)

Операции подстановки выполняются как замена значения некоей части сообщения (часто в 4, 6 или 8 бит) на стандартное, жестко встроенное в алгоритм иное число путем обращения к константному массиву. Операция подстановки привносит в алгоритм нелинейность.

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

Существует множество (не менее двух десятков) алгоритмов симметричных шифров, существенными параметрами которых являются:

- стойкость;

- длина ключа;

- число раундов;

- длина обрабатываемого блока;

- сложность аппаратной/программной реализации;

- сложность преобразования.

Распространенные алгоритмы:

- AES (англ. Advanced Encryption Standard) - американский стандарт шифрования

- ГОСТ 28147-89 -- отечественный стандарт шифрования данных;

- DES (англ. Data Encryption Standard) - стандарт шифрования данных в США до AES;

- 3DES (Triple-DES, тройной DES);

- RC6 (Шифр Ривеста );

- Twofish;

- IDEA (англ. International Data Encryption Algorithm);

- SEED - корейский стандарт шифрования данных;

- Camellia - сертифицированный для использовании в Японии шифр;

- CAST (по инициалам разработчиков Carlisle Adams и Stafford Tavares);

- XTEA - наиболее простой в реализации алгоритм.

Отбросив устаревшие и специфичные стандарты, остановимся на двух наиболее подходящих для данного проекта: AES и ГОСТ 28147-89.

Advanced Encryption Standard (AES), также известный как Rijndael -- симметричный алгоритм блочного шифрования (размер блока 128 бит, ключ 128/192/256 бит), принятый в качестве стандарта шифрования правительством США по результатам конкурса AES[6]. Этот алгоритм хорошо проанализирован и сейчас широко используется, как это было с его предшественником DES. Национальный институт стандартов и технологий США (англ. National Institute of Standards and Technology, NIST) опубликовал спецификацию AES 26 ноября 2001 года после пятилетнего периода, в ходе которого были созданы и оценены 15 кандидатур. 26 мая 2002 года AES был объявлен стандартом шифрования. По состоянию на 2009 год AES является одним из самых распространённых алгоритмов симметричного шифрования. Поддержка AES (и только его) введена фирмой Intel в семейство процессоров x86 начиная с Intel Core i7-980X Extreme Edition, а затем на процессорах Sandy Bridge.

ГОСТ 28147-89 -- советский и российский стандарт симметричного шифрования, введённый в 1990 году, также является стандартом СНГ. Полное название -- «ГОСТ 28147-89 Системы обработки информации. Защита криптографическая. Алгоритм криптографического преобразования». Блочный шифроалгоритм. При использовании метода шифрования с гаммированием, может выполнять функции поточного шифроалгоритма.

По некоторым сведениям, история этого шифра гораздо более давняя. Алгоритм, положенный впоследствии в основу стандарта, родился, предположительно, в недрах Восьмого Главного управления КГБ СССР (ныне в структуре ФСБ), скорее всего, в одном из подведомственных ему закрытых НИИ, вероятно, ещё в 1970-х годах в рамках проектов создания программных и аппаратных реализаций шифра для различных компьютерных платформ.

С момента опубликования ГОСТа на нём стоял ограничительный гриф «Для служебного пользования», и формально шифр был объявлен «полностью открытым» только в мае 1994 года. История создания шифра и критерии разработчиков по состоянию на 2010 год не опубликованы.

ГОСТ 28147-89 -- блочный шифр с 256-битным ключом и 32 циклами преобразования, оперирующий 64-битными блоками. Основа алгоритма шифра -- Сеть Фейстеля. Базовым режимом шифрования по ГОСТ 28147-89 является режим простой замены (определены также более сложные режимы гаммирование, гаммирование с обратной связью и режим имитовставки).

В ГОСТе используется 256-битовый ключ и объем ключевого пространства составляет 2256. Ни на одном из существующих в настоящее время или предполагаемых к реализации в недалеком будущем электронном устройстве нельзя подобрать ключ за время, меньшее многих сотен лет. Эта величина стала фактическим стандартом размера ключа для симметричных криптоалгоритмов в наши дни, - так, новый стандарт шифрования США также его поддерживает. Прежний же американский стандарт, DES с его реальным размером ключа в 56 бит и объемом ключевого пространства всего 256 уже не является достаточно стойким в свете возможностей современных вычислительных средств. Это было продемонстрировано в конце 90-х годов несколькими успешными попытками взлома DES переборным путем. Кроме того, DES оказался подвержен специальным способам криптоанализа, таким как дифференциальный и линейный. В этой связи DES может представлять скорее исследовательский или научный, чем практический интерес. В 1998 году его криптографическая слабость была признана официально, - национальный институт стандартов США рекомендовал использовать троекратное шифрование по DES. А в конце 2001 года был официально утвержден новый стандарт шифрования США, AES, построенный на иных принципах и свободный от недостатков своего предшественника.

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

Алгоритмы «основных шагов криптопреобразования» для шифров, подобных ГОСТу, построены идентичным образом, и эта архитектура называется сбалансированная сеть Файстеля (balanced Feistel network) по имени человека, впервые предложившего ее. Схема преобразования данных на одном цикле(раунде) приведена на рисунке 1.7.

Рисунок 1.7 - Содержание основного шага криптопреобразования для блочных шифров, подобных ГОСТу.

На вход основного шага подается блок четного размера, старшая и младшая половины которого обрабатываются отдельно друг от друга. В ходе преобразования младшая половина блока помещается на место старшей, а старшая, скомбинированная с помощью операции побитового «исключающего или» с результатом вычисления некоторой функции, на место младшей. Эта функция, принимающая в качестве аргумента младшую половину блока и элемент ключевой информации (X), является содержательной частью шифра и называется его функцией шифрования. По разным соображениям оказалось выгодно разделить шифруемый блок на две одинаковые по размеру части: |N 1|=|N 2| - именно этот факт отражает слово «сбалансированная» в названии архитектуры. Впрочем, шифрующие несбалансированные сети также используются время от времени, хотя и не так часто, как сбалансированные. Кроме того, соображения стойкости шифра требуют, чтобы размер ключевого элемента не был меньше размера половины блока: в ГОСТе все три размера равны 32 битам.

Если применить сказанное к схеме основного шага алгоритма ГОСТ, станет очевидным, что блоки 1,2,3 алгоритма определяют вычисление его функции шифрования, а блоки 4 и 5 задают формирование выходного блока основного шага исходя из содержимого входного блока и значения функции шифрования.

Сравним DES и ГОСТ по функциональному содержанию и удобству реализации. В циклах шифрования ГОСТа основной шаг повторяется 32 раза, для DES эта величина равна 16. Однако сама функция шифрования ГОСТа существенно проще аналогичной функции DES, в которой присутствует множество нерегулярных битовых перестановок. Эти операции чрезвычайно неэффективно реализуются на современных неспециализированных процессорах. ГОСТ не содержит подобных операций, поэтому он значительно удобней для программной реализации.

Ни одна из реализаций DESа для платформы Intel x86 не достигает даже половины производительности предложенной в настоящей реализации ГОСТа несмотря на вдвое более короткий цикл. Все сказанное выше свидетельствует о том, что разработчики ГОСТа учли как положительные, так и отрицательные стороны DESа, а также более реально оценили текущие и перспективные возможности криптоанализа. Впрочем, брать DES за основу при сравнении быстродействия реализаций шифров уже не актуально. У нового стандарта шифрования США дела с эффективностью обстоят гораздо лучше - при таком же как у ГОСТа размере ключа в 256 бит AES работает быстрее него примерно на 14% - это если сравнивать по числу «элементарных операций». Кроме того, ГОСТ практически не удается распараллелить, а у AES возможностей в этом плане намного больше. На некоторых архитектурах это преимущество AES может быть меньше, на других - больше. Так, на процессоре Intel Pentium оно достигает 28%. Процессоры Intel Core за счет аппаратной поддержки стандарта демонстрируют значительное преимущество в скорости шифрования AES.

Кроме того, в мае 2011 года известный криптоаналитик Николя Куртуа заявил об обнаружении серьезных уязвимостей в ГОСТ. Практический результат пока скромен: 2^64 известных открытых текста и 2^64 памяти для хранения пар “открытый текст/шифртекст” позволяют взломать ГОСТ в 2^8 быстрее, чем простой перебор. Но в плане криптоанализа это делает полностью справедливым утверждение о том, что “ГОСТ взломан”. Так же у ГОСТ есть и другие недостатки. Основные проблемы ГОСТа связаны с неполнотой стандарта в части генерации ключей и таблиц замен. Тривиально доказывается, что у ГОСТа существуют «слабые» ключи и таблицы замен, но в стандарте не описываются критерии выбора и отсева «слабых». Также стандарт не специфицирует алгоритм генерации таблицы замен (S-блоков). С одной стороны, это может являться дополнительной секретной информацией (помимо ключа), а с другой, поднимает ряд проблем:

- нельзя определить криптостойкость алгоритма, не зная заранее таблицы замен;

- реализации алгоритма от различных производителей могут использовать разные таблицы замен и могут быть несовместимы между собой;

- возможность преднамеренного предоставления слабых таблиц замен лицензирующими органами РФ;

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

Исходя из этого, выберем AES для шифрования данных в нашей компоненте.

Схема основного алгоритма программы приведена на рисунке 1.8. Схема алгоритма обработки дополнительных событий от сервера показана на рисунке 1.9.

Рисунок1.8- Схема алгоритма программы

Рисунок1.9- Схема алгоритма проверки дополнительных событий от сервера телефонии

1.5 Разработка алгоритма AES

AES -- относительно новый криптографический алгоритм для защиты электронных данных. Точнее, AES -- это итеративный блочный шифр с симметричным ключом, который использует 128-, 192- и 256-битные ключи и шифрует/дешифрует данные блоками по 128 битов (16 байтов). В отличие от шифров с открытым ключом, использующих пару ключей, шифры с симметричным ключом применяют для шифрования и дешифрования данных один и тот же ключ [6]. Зашифрованные данные, возвращаемые блочным шифром, содержат ровно столько же битов, сколько и входные данные. При итеративном шифровании выполняется цикл, на каждой итерации которого над входными данными выполняются операции перестановки (пермутации) и замены. Ниже показан пример использования AES: 16-байтный блок данных шифруется 192-битным ключом, а затем дешифруется.

Исходный текст:

00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff

192-битный ключ:

00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17

Зашифрованныйтекст:

dd a9 7c a4 86 4e df e0 6e af 70 a0 ec 0d 71 91

Результат расшифровки:

00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff

Предшественником AES является старый стандарт DES (Data Encryption Standard). DES утвердили в качестве федерального стандарта в 1977 г. Он считался пригодным для использования до 1998 г., когда оказалось, что с помощью новейших достижений аппаратно-программного обеспечения и криптографического анализа можно расшифровать сообщение, зашифрованное по алгоритму DES, за 50 часов. С тех пор начались многочисленные успешные атаки на данные, зашифрованные по алгоритму DES. Поэтому в настоящее время DES считается устаревшим, В конце 1999 г. NIST предложил использовать в новом стандарте алгоритм Rijndael (произносится как «rain doll»), разработанный исследователями Джоан Демен (Joan Daemen) и Винсентом Риджменом (Vincent Rijmen), как в наибольшей степени отвечающий критериям безопасности, эффективности реализации, гибкости и простоты. Термины AES и Rijndael иногда употребляются как синонимы, но это разные понятия. Ожидается, что AES станет стандартом де-факто в шифровании всех видов электронных данных, в том числе используемых коммерческими приложениями (например для банковских и финансовых транзакций), в телекоммуникациях, при передаче частной и правительственной информации.

Алгоритм AES основан на перестановках (permutations) и заменах (substitutions). Перестановка -- это изменение порядка данных, а замена - замещение одного блока данных другим. В AES используется несколько видов перестановок и замен. Чтобы в них разобраться, рассмотрим конкретный пример -- шифрование по алгоритму AES данных, показанное в примере выше.

Здесь шифруется следующее 128-битное значение (во второй строке показаны индексы массива):

00 11 22 33 44 55 66 77 88 99 аа bb cc dd ее ff

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

и используется 192-битный исходный ключ:

00 01 02 03 04 05 06 07 08 09 0a 0b 0с 0d 0e 0f 10 11 12 13 14 15 16 17

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

При вызове конструктора AES-класса инициализируются две таблицы, используемые методом шифрования. Первая таблица -- матрица замен Sbox размером 16x16. Первые пять строк и столбцов Sbox показаны в таблице1.2.

Таблица 1.2 - Первые пять строк и столбцов матрицы замен Sbox

x\y

0

1

2

3

4

0

63

7c

77

7b

f2

1

ca

82

c9

7d

fa

2

b7

fd

93

26

36

3

04

c7

23

c3

18

4

09

83

2c

1a

1b

Кроме того, в процедуре шифрования по массиву байтов ключа формируется «таблица ключей» («key schedule») w[], показанная в таблице 1.3.

Таблица1.3 - Таблица ключей

0

00

01

02

03

1

04

05

06

07

2

08

09

0a

0b

3

0c

0d

0e

0f

4

10

11

12

13

5

14

15

16

17

6

58

46

f2

f9

7

5c

43

f4

fe

8

54

48

fe

f5

9

58

47

f9

fa

10

48

56

e2

e9

...

...

...

...

...

49

fa

76

dc

09

50

c4

18

c2

7d

51

e3

a4

1d

5d

Первые Nk (в данном случае Nk = 6) строк w[ ] заполняются значением исходного ключа (от 0x00 до 0x17), а остальные строки генерируются по исходному ключу (seed key). Переменная Nk -- это размер исходного ключа в 32-битных словах. В дальнейшем, при описании реализации AES, можно будет увидеть, как именно генерируются элементы w[ ]. Дело в том, что в AES применяется несколько ключей вместо одного. Эти новые ключи называются итеративными (round keys), чтобы подчеркнуть их отличие от исходного ключа, задаваемого при вызове процедуры шифрования.

Сначала подпрограмма шифрования по алгоритму AES копирует 16-байтный входной массив в матрицу State (таблица 1.4) размером 4x4.

Таблица1.4 - Матрица State

0

1

2

3

0

00

44

88

сс

1

11

55

99

dd

2

22

66

aa

ee

3

33

77

bb

ff

Процедура шифрования называется Cipher. Она работает с матрицей State[ ] и описывается псевдокодом, приведенным в распечатке 1.4.Псевдокод - язык описания алгоритмов, использующий ключевые слова языков программирования, но опускающий подробности и специфический синтаксис.

Распечатка 1.4

Cipher(byte[] input, byte[] output)

{

byte[4,4] State;

Копирование input[] s State[]

AddRoundKey

for (round = 1; round < Nr-1; ++round)

{

SubBytes

ShiftRows

MixColumns

AddRoundKey

}

SubBytes

Shift Rows

AddRoundKey

Копирование Stated в output[]

}

Алгоритм шифрования выполняет операцию предварительной обработки, которая в спецификации называется AddRoundKey. AddRoundKey выполняет над каждым байтом входной матрицы State операцию XOR с первыми четырьмя строками таблицы ключей. Байту State[r,c] присваивается результат операции XOR с элементом таблицы ключей w[c,r], т. е. State[r,c] = State[r,c] XOR w[c,r].

Например, если первая строка матрицы State содержит байты {00, 44, 88, cc}, а первый столбец таблицы ключей имеет вид {00,04, 08, 0с}, то новым значением State[0,2] будет 0x80 -- результат операции XOR над State[0,2] (0x88) и w[2,0] (0x08):

1 0 0 0 1 0 0 0

0 0 0 0 1 0 0 0 XOR

1 0 0 0 0 0 0 0

В основном цикле алгоритма шифрования AES выполняются четыре операции над матрицей State, которые в спецификации называются SubBytes, ShiftRows, MixColumns и AddRoundKey. Операция AddRoundKey -- то же, что и предварительная операция AddRoundKey с тем исключением, что при каждом вызове AddRoundKey используются следующие четыре строки таблицы ключей. Подпрограмма SubBytes выполняет операцию замены: замещает каждый байт матрицы State новым байтом, определяемым по таблице Sbox. Например, пусть значением State[0,1] является 0x40 и требуется найти его замену. Берется значение State[0,1] (0x40), и переменной х присваивается его левая цифра (4), а переменной у -- правая (0). Затем по индексам х и у из таблицы Sbox берется значение замены.

ShiftRows -- это операция перестановки, при которой байты матрицы State циклически сдвигаются влево. В таблице 1.5 показано, как ShiftRows обрабатывает State[ ]. Строка 0 матрицы State циклически сдвигается на 0 позиций влево, строка 1 -- на одну позицию влево, строка 2 -- на две позиции влево, а строка 3 -- на три позиции влево.

Таблица1.5 - Обработка State операцией ShiftRows

0

1

2

3

0

00

44

88

сс

1

11

55

99

dd

2

22

66

aa

ee

3

33

77

bb

ff

MixColumns -- это операция замены, самая сложная для понимания часть алгоритма AES. Она заменяет каждый байт результатом математических операций сложения и умножения в поле (mathematical field additions and multiplications), применяемых к элементам столбца, который содержит этот байт. Я расскажу о сложении и умножении элементов полей в следующем разделе.

Допустим, значением State[0,1] является 0x09, а остальные элементы столбца 1 -- 0x60, 0xe1 и 0x04; тогда новым значением State[0,1] будет результат следующего выражения:

+

Здесь сложение и умножение - это специальные математические операции над элементами поля, а не обычное целочисленное сложение и умножение.

Четыре подпрограммы SubBytes, ShiftRows, MixColumns и AddRoundKey вызываются в цикле, выполняемом Nr - 1 раз, где Mr - число итераций для ключа данного размера, Количество итераций алгоритма шифрования равно 10, 12 или 14 в зависимости от размера исходного ключа (128, 192 или 256 бит). В нашем примере Nr равно 12, поэтому четыре операции вызываются 11 раз. По завершении цикла алгоритм шифрования еще раз вызывает SubBytes, ShiftRows и AddRoundKey, а затем копирует матрицу State в выходной параметр.

Подведем итог: ядро алгоритма AES-шифрования образуют четыре операции. AddRoundKey заменяет группы из 4 байтов, комбинируя их с итеративными ключами, которые генерируются по значению исходного ключа. SubBytes замещает отдельные байты в соответствии с таблицей замен. ShiftRows переставляет группы из 4 байтов, циклически сдвигая 4-байтовые строки. MixColumns заменяет байты результатами операций сложения и умножения элементов поля.

Как видно, алгоритм шифрования AES использует достаточно простые операции перестановки и замены, если не считать процедуры MixColumns. В MixColumns применяются специальные операции сложения и умножения. Сложение и умножение в AES основаны на математической теории полей. А конкретнее, в AES используется поле GF(28).

Поле GF(28) состоит из 256 значений от 0x00 до 0xff, над которыми определены операции сложения и умножения. Отсюда (28) в названии. Поле GF (Galois Field) названо в честь Галуа, математика, основавшего теорию полей. Одной из характеристик GF(28) является то, что результат сложения или умножения всегда принадлежит множеству {0x00 … 0xff}. Теория полей достаточно сложна, но применительно к сложению в GF(28) получается простой конечный результат: сложение в GF(28) -- это обыкновенная операция XOR.

Однако умножение в GF(28) -- более сложная операция. Как в дальнейшем увидим в реализации на С#, в процедурах шифрования и дешифрования алгоритма AES используется умножение только на семь констант:

0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d и 0х0е. Поэтому вместо объяснения общей теории умножения в GF(28) ограничимся рассмотрением этих семи частных случаев.

Умножение на 0x01 в GF(28) занимает особое место; оно соответствует умножению на 1 в обычной арифметике и выполняется точно так же: при умножении любого значения на 0x01 получается то же самое значение.

Теперь рассмотрим умножение на 0x02. Как и в случае сложения, теория трудна, зато результат сравнительно прост. Если умножаемое значение меньше 0x80, оно сдвигается влево на 1 бит. Если же умножаемое значение больше или равно 0x80, оно сначала сдвигается влево на 1 бит, а затем к результату сдвига применяется операция XOR со значением 0x1b. Тем самым предотвращается «переполнение поля», и результат умножения остается в допустимом диапазоне.

Освоив операции сложения и умножения на 0x02 в поле GF(28), можем выразить через них умножение на любую константу. При умножении на 0x03 в GF(28) значение 0x03 можно представить как сумму степеней числа 2. Чтобы умножить произвольный байт b на 0x03, представьте 0x03 как 0x02 + 0x01. Следовательно:

Эту операцию можно выполнить, зная, как умножать на 0x02 и 0x01 и как складывать. Аналогично умножение произвольного байта на 0x0d сводится к следующим операциям:

Другие операции умножения, необходимые процедуре MixColumns при шифровании и дешифровании по алгоритму AES, выполняются по тому же универсальному шаблону:

Подведем итог. Сложение в GF(28) -- это операция XOR. Умножение в GF(28) сводится к операциям сложения и умножения на 0x02, а умножение на 0x02 -- это сдвиг на 1 бит влево, выполняемый в зависимости от условия.

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

Распечатка 1.5

KeyExpansion(byte[] key, byte[][4] w)

{

Копирование исходного ключа в первые строки w

Для каждой оставшейся строки w

{

Создание новой строки по двум предыдущим

}

Процедура «создание новой строки по двум предыдущим» использует две подпрограммы, Rot Word и Sub Word, а также таблицу констант Rcon (аббревиатура от round constants -- итеративные константы). Рассмотрим каждый из этих трех элементов, а потом вернемся к подпрограмме KeyExpansion в целом.

Подпрограмма RotWord не сложна в реализации. Она принимает массив из 4 байтов и циклически сдвигает их на 1 позицию влево. В таблице ключей w[ ]четыре столбца, и RotWord сдвигает заданную строку w[ ] влево. Заметьте: функция RotWord, вызываемая KeyExpansion, очень похожа на подпрограмму ShiftRows, используемую алгоритмом шифрования, с тем исключением, что применяется к одной строке таблицы ключей w[ ], а не ко всей таблице состояния State[ ].

Подпрограмма SubWord выполняет побайтовую замену заданной строки таблицы ключей w[ ] в соответствии с Sbox. Замена в KeyExpansion выполняется так же, как и в алгоритме шифрования. Входной байт, который замещается, разбивается на пару (х,у), задающую индексы в таблице замен Sbox. Например, замена 0x27 дает х = 2 и у = 7, a Sbox[2,7] возвращает 0хсс.

Подпрограмма KeyExpansion использует массив Rcon[ ], называемый таблицей итеративных констант. Каждая из этих констант содержит 4 байта, соответствующие строке таблицы ключей. В AES-подпрограмме KeyExpansion используется 11 итеративных констант, как показано в распечатке 1.6.

Распечатка 1.6

private void BuildRcon()

{

this.Rcon = new byte[11,4] { {0x00, 0x00, 0x00, 0x00},

{0x01, 0x00, 0x00, 0x00},

{0x02, 0x00, 0x00, 0x00},

{0x04, 0x00, 0x00, 0x00},

{0x08, 0x00, 0x00, 0x00},

{0x10, 0x00, 0x00, 0x00},

{0x20, 0x00, 0x00, 0x00},

{0x40, 0x00, 0x00, 0x00},

{0x80, 0x00, 0x00, 0x00},

{0x1b, 0x00, 0x00, 0x00},

{0x36, 0x00, 0x00, 0x00} };

} // BuildRcon()

Левыйбайткаждойитеративнойконстанты -- этостепеньчисла 2 вполеGF(28). Еще один способ вычисления значений этого байта -- умножать каждое предыдущее значение на 0x02 в соответствии с правилами умножения в поле GF(28), приведенным в предыдущем разделе. Заметьте: 0x80 · 0x02 = 0x36, так как 0x80 сдвигается влево на 1, а затем над результатом сдвига выполняется XOR с 0x1b.

Теперь более пристально рассмотрим цикл подпрограммы KeyExpansion. Если детализировать показанный выше псевдокод, этот цикл приобретет следующий вид, показанный в распечатке 1.7.

Распечатка 1.7

for (row = Nk; row < (4 * Nr+1); ++row)

{

temp = w[row-1]

if (row % Nk == 0)

temp = SubWord(RotWord(temp)) xor Rcon[row/Nk]

else if (Nk == В and row % Nk == 4)

temp = SubWord(temp)

w[row] = w[row-Nk] xor temp

}

Если пока отвлечься от операторов if, то видно, что каждая строка таблицы ключей w[ ] -- результат XOR предыдущей строки со строкой, находящейся на Nk (4, б или 8 в зависимости от размера ключа) строк выше. Первое условие if означает, что к каждой четвертой, шестой или восьмой строке (в зависимости от размера ключа -- 128,192 или 256 битов) применяются подпрограммы SubWord, RotWord, а затем -- операция XOR с итеративной константой. Второе условие означает, что в случае 256-битного ключа изменяются строки 12, 20, 28 и так далее через восемь строк. Это делается для того, чтобы в таблице ключей содержались более разнообразные значения.

Посмотрим, как KeyExpansion приступает к обработке ключа, показанного в исходном примере. Исходный ключ -- 192-битное значение (6 слов):

00 01 02 03 04 05 06 07 08 09 0а 0b 0с 0d 0e 0f 10 11 12 13 14 15 16 17

В таблице ключей w[ ] 4 столбца и Nb x (Nr + 1) = 4 х (12 + 1) = 52 строки.

Подпрограмма KeyExpansion копирует значения исходного ключа в первые строки таблицы ключей w[ ], содержащей байты. Поскольку исходный ключ содержит 192 бита (24 байта), а таблица w[ ] всегда содержит 4 столбца, в данном случае KeyExpansion копирует исходный ключ в первые 6 строк w[ ]. Как KeyExpansion заполняет остальные строки таблицы ключей? В данном примере первой вычисляемой строкой является строка 6, поскольку строки от 0 до 5 заполнены значениями исходного ключа:

temp = w[row-1] = 14 15 16 17

Условие (row % Nk == 0) истинно, поэтому к строке применяется подпрограмма RotWord:

temp = 15 16 17 14

Затем применяется подпрограмма SubWord:

temp = 59 47 f0 fa

Далее выполняется XOR с Rcon[row / Nk] - Rcon[6 / 6] = 01 00 00 00:

temp = 58 47 f0 fa

Наконец, выполняется XOR с w[row-Nk] = w[6-6] = 00 01 02 03, и в результате получается строка:

w[6] = 58 46 f2 f9

Этот процесс повторяется для остальных строк таблицы ключей w[ ].

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

Теперь рассмотрим некоторые важные альтернативы той реализации AES, которая была показана здесь, возможные расширения кода и потенциально вероятные попытки взлома AES.

Как и любой алгоритм, AES можно реализовать разными способами. Почему это важно? AES рассчитан на применение в широком спектре систем -- от смарт-карт с крохотной памятью до громадных многопроцессорных мэйнфреймов. Во многих случаях критически важна производительность, иногда приходится сталкиваться с ограниченностью памяти или других ресурсов обработки данных. Почти каждую подпрограмму AES можно изменить, оптимизировав производительность за счет памяти, или наоборот. Например, присвоение 256 значений элементам таблицы замен Sbox[ ] выглядит вроде бы достаточно прямолинейно. Но эти значения вычисляются в соответствии с теорией GF(28), и их можно генерировать программно. То же относится к таблице обратных замен и таблице итеративных констант.

Еще одна интересная возможность -- разные способы реализации умножения в GF(28), используемого методами Cipher и InvCipher. Была написана базовая функция gfmultby02, умножающая на 0x02, и шесть дополнительных функций, вызывающих ее. Альтернатива -- написать универсальную функцию умножения и использовать ее, а не семь разных функций, как в данной реализации. Или экстремальный вариант -- составить полную таблицу произведений всех 256 возможных значений байта на 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d и 0х0е. Еще один способ умножения в GF(28) -- реализовать умножение как поиск в двух 256-байтовых массивах, обычно называемых alog[ ] и log[ ], поскольку такое умножение основано на некоторых свойствах GF(28), аналогичных свойствам логарифмов.

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

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

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

1.6 Разработка текста программы

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

Для начала необходимо, чтобы компонента реализовывала COM-соединение с 1С.

1С:Предприятие подключает внешнюю компоненту двумя способами: по указанному ProgID через CreateInstance, либо по имени файла компоненты. В последнем случае 1С пытается выполнить DllRegisterServer для саморегистрации файла через rgs-скрипт, затем ищется строка с ID=100 из ресурсов компоненты, содержащая ProgID объекта. При написании CLR-кода последняя возможность отпадает, поскольку у NET-компонент совсем другой принцип регистрации и другой метод хранения ресурсов. Поэтому из 1С:Предприятия необходимо использовать только метод ПодключитьВнешнююКомпоненту(ProgID), где ProgID должен иметь вид AddIn.xxx, для чего используется атрибут ProgIdAttribute.

Ключевым для работы внешней компоненты является интерфейс IInitDone (Распечатка 1.8).

Распечатка 1.8

[Guid("AB634001-F13D-11d0-A459-004095E1DAEA")]

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

public interface IInitDone

{

// Инициализациякомпонента

void Init(

[MarshalAs(UnmanagedType.IDispatch)]

object connection);

// Вызывается перед уничтожением компонента

void Done();

// Возвращается инициализационная информация

voidGetInfo(

[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_VARIANT)]

ref object[] info);

}

Кроме того, библиотека типов, поставляемая фирмой 1С, содержит ряд других интерфейсов для расширения встроенного языка и других целей, рассматривать которые мы не будем. Конечно можно воспользоваться готовым tlb-файлом и средствами NET создать COM callable wrapper (проще говоря добавить ссылку на COM-библиотеку из проекта), но тогда следует согласится с тем, что множество параметров типа VARIANT будут преобразованы в малоудобные System.Array или Object, в то время как из документации известна их более строгая типизация. Наш интерфейс в NET будет выглядеть, как показано в распечатке 1.9.

Распечатка 1.9

private IAsyncEvent asyncEvent = null;

private IStatusLine statusLine = null;

public void Init(

[MarshalAs(UnmanagedType.IDispatch)]

object connection)

{

asyncEvent = (IAsyncEvent)connection;

statusLine = (IStatusLine)connection;

}

public void GetInfo(

[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_VARIANT)]

ref object[] info)

{

info[0] = 2000;

}

Интерфейс IAsyncEvent реализован 1С для получения событий от внешнего компонента. Ссылка на него получена путем приведения параметра функции Init интерфейса IInitDone к типу IAsyncEvent при инициализации компонента. Внешнее событие обрабатывается 1С в функции ОбработкаВнешнегоСобытия.

В распечатке 1.10 показан текст реализованного в компонентеинтерфейсаIAsyncEvent.

Распечатка 1.10

[Guid("AB634004-F13D-11D0-A459-004095E1DAEA"),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

public interface IAsyncEvent

{

void SetEventBufferDepth(Int32 depth);

void GetEventBufferDepth(ref Int32 depth);

void ExternalEvent([MarshalAs(UnmanagedType.BStr)] String source,

[MarshalAs(UnmanagedType.BStr)] String message,

[MarshalAs(UnmanagedType.BStr)] String data);

void CleanBuffer();

}

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

Для начала создадим подключение, как показано в распечатке 1.11.

Распечатка 1.11

TcpClient tcpSocket;

string Hostname = "sip.miko.ru";

int Port = 5038;

tcpSocket = new TcpClient(Hostname, Port);

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

Распечатка 1.12

stringres = "Action: Login" + "\r\n"

+ "ActionID: " + ActionID + "\r\n"

+ "Username: " + Username + "\r\n"

+ "Secret: " + Secret + "\r\n";

SendString(tcpSocket, res);

ЗдесьSendString(tcpSocket, res) - функция, котораяпосылаетстрокувпоток. Еекодпредставленвраспечатке 1.13.

Распечатка 1.13

publicstaticvoidSendString(TcpClienttcpSocket, stringStroka) //Послатьстрокувпоток

{

Stroka = Stroka + "\r\n";

byte[] buf = Encrypt(System.Text.ASCIIEncoding.ASCII.GetBytes(Stroka));

tcpSocket.GetStream().Write(buf, 0, buf.Length);

}

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

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

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

Потоки имеют следующие свойства.

- потоки позволяют программе выполнять параллельную обработку;

- пространство имен .NET Framework System.Threading упрощает использование потоков;

- потоки используют одни и те же ресурсы приложения.

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

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

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

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

Выше мы рассмотрели все компоненты алгоритма шифрования AES, и теперь реализуем этот алгоритм на С#. ОфициальнаяспецификацияалгоритмаAESсодержитсявдокументеFederalInformationProcessingStandardsPublication 197[6]. Было решено, что реализация должна соответствовать ей максимально точно, но вскоре было обнаружено, что спецификация скорее теоретический документ, чем руководство по реализации. Для удобства было решено использовать те же имена переменных, что и в опубликованном стандарте (даже такие загадочные, как «Nr> и «w»).

В реализации девять полей данных и один перечислимый тип, как показано в распечатке 1.14.

Распечатка 1.14

public enum KeySize { Bits128, Bits192, Bits256 };

private int Nb;

private int Nk;

private int Nr;

private byte[] key;

private byte[,] Sbox;

private byte[,] iSbox;

private byte[,] w;

private byte[,] Rcon;

private byte[,] State;

Поскольку ключи бывают только 128-, 192- и 256-битные, для описания размера ключа очень удобно создать перечислимый тип:

public enum KeySize { Bits128, Bits192, Bits256 };

Как правило, в спецификации в качестве единицы хранения данных используются байты, но имеется два важных поля, задающих размер в 4-байтовых словах. Члены Nb и Nk содержат соответственно размер блока в словах и размер ключа в словах. Nr задает количество циклов. Размер блока -- всегда 16 байтов (или 128 битов, т.е. 4 слова в терминологии AES), так что можно было бы объявить его константой. Размеру ключа присваивается значение 4, 6 или 8 в зависимости от значения перечислимого параметра KeySize. Чтобы усложнить зашифрованные данные, алгоритм AES содержит цикл, выполняемый заданное число раз -- 10, 12 или 14. Эти значения выбраны в соответствии с теорией криптографического анализа. Количество циклов напрямую зависит от размера ключа.

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

Aes a = new Аеs(размер ключа, исходный ключ)

Подпрограммы шифрования и дешифрования вызываются, как показано в распечатке 1.15.

Распечатка 1.15

а.Cipher(plainText, cipherText);

a.InvCipher(cipherText, decipheredText);

Быливыбраныслегканеуклюжиеименаметодов Cipher и InvCipher, посколькуонииспользуютсявспецификации AES. Код конструктора AES-класса представлен в распечатке 1.16.

Распечатка 1.16

publicAes(KeySizekeySize, byte[] keyBytes)

{

SetNbNkNr(keySize);

this.key = new byte[this.Nk * 4];

keyBytes.CopyTo(this.key, 0);

BuildSbox();

BuildlnvSbox();

BuildRcon();

KeyExpansion();

}

Сначала конструктор присваивает значения полям Nb, Nk и Nr, вызывая вспомогательный метод SetNbNkNr, приведенный в распечатке 1.17.

Распечатка 1.17

private void SetNbNkNr(KeySize keySize)

{

this.Nb = 4; // block size always = 4 words = 16 bytes = 128 bits for AES

if (keySize == KeySize.Bits128)

{

this.Nk = 4; // key size = 4 words = 16 bytes = 128 bits

this.Nr = 10; // rounds for algorithm = 10

}

else if (keySize == KeySize.Bits192)

{

this.Nk = 6; // 6 words = 24 bytes = 192 bits

this.Nr = 12;

}

else if (keySize == KeySize.Bits256)

{

this.Nk = 8; // 8 words = 32 bytes = 256 bits

this.Nr = 14;

}

} // SetNbNkNr()

Затем байты, передаваемые конструктору, копируются в поле класса. Ключ объявлен как поле класса и инициализируется операторами (распечатка 1.18).

Распечатка 1.18

this.key = new byte[this.Nk * 4];

keyBytes.CopyTo(this.key, 0);

Для инициализации таблиц замен Sbox[ ] и iSbox[ ] было решено вызывать в конструкторе закрытые вспомогательные методы BuildSbox и Buildlnv-Sbox. Таблицы Sbox[ ] и iSbox[ ] необходимы подпрограмме расширения ключа и методам Cipher и InvCipher соответственно, поэтому можно было бы поместить инициализацию Sbox[| и вызов метода Key Expansion в методы Cipher и InvCipher. Но код, который выполняет эти операции в конструкторе, выглядит понятнее. Как заполняется sBox[ ], показано на распечатке 1.19. Таблица iSbox[ ] заполняется аналогично. Для удобства чтения код структурирован.

Распечатка 1.19

privatevoidBuildSbox()

{

this.Sbox = newbyte[16,16] { // populatetheSboxmatrix

/* 0 1 2 3 4 5 6 7 8 9 abcdef */

/*0*/ {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},

/*1*/ {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},

/*2*/ {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},

/*3*/ {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},

/*4*/ {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},

/*5*/ {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},

/*6*/ {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},

/*7*/ {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},

/*8*/ {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},

/*9*/ {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},

/*a*/ {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},

/*b*/ {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},

/*c*/ {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},

/*d*/ {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e},

/*e*/ {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf},

/*f*/ {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16} };

} // BuildSbox()

Лучше всего объявить таблицу ключей w[ ], таблицу итеративных констант Rcon[ ] и таблицу State[ ] членами класса и присваивать значения таблицам Rcon[ ] и w[ ] закрытыми вспомогательными методами.

Вспомним, что левый байт каждой строки Rcon[ ] -- это степень 2 в поле GF(28), следовательно, эту таблицу можно заполнить, выполнив вычисления вида:

newVal = prevVal * 0x02;

В конце конструктора AES-класса вызывается метод KeyExpansion, формирующий таблицу ключей w[ ]. Код метода довольно прост. В спецификации используется гипотетический тип данных -- 4-байтное слово. В С# такого типа нет, поэтому он был смоделирован как массив из 4 байтов. Сначала таблице w[ ]выделяется память оператором new. Затем первые Nk (4, 6 или 8) строк w[ ] заполняются значениями массива key[ ], передаваемого конструктору (распечатка 1.20).

Распечатка 1.20

this.w[row,0] = this.key[4*row];

this.w[row,1] = this.key[4*row+1];

this.w[row,2] = this.key[4*row+2];

this.w[row,3] = this.key[4*row+3];

private void KeyExpansion()

{

this.w = new byte[Nb * (Nr+1), 4]; // 4 columns of bytes corresponds to a word

for (int row = 0; row < Nk; ++row)

{

this.w[row,0] = this.key[4*row];

this.w[row,1] = this.key[4*row+1];

this.w[row,2] = this.key[4*row+2];

this.w[row,3] = this.key[4*row+3];

}

byte[] temp = new byte[4];

for (int row = Nk; row < Nb * (Nr+1); ++row)

{

temp[0] = this.w[row-1,0]; temp[1] = this.w[row-1,1];

temp[2] = this.w[row-1,2]; temp[3] = this.w[row-1,3];

if (row % Nk == 0)

{

temp = SubWord(RotWord(temp));

temp[0] = (byte)( (int)temp[0] ^ (int)this.Rcon[row/Nk,0] );

temp[1] = (byte)( (int)temp[1] ^ (int)this.Rcon[row/Nk,1] );

temp[2] = (byte)( (int)temp[2] ^ (int)this.Rcon[row/Nk,2] );


Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.