Понятия, необходимые для описания алгоритма AES

Введение

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

Описание алгоритма

Алгоритм AES- симметричный криптоалгоритмом блочного шифрования. Является упрощенным вариантом криптоалгоритма Rijndael.Размер блока шифрования фиксирован и составляет 128 бит, это и есть отличие AES от Rijndael, в последнем длина блока может варьироваться. Размер ключа может быть равным 128, 192, либо 256 бит.

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

Описание операций поля GF(28)

Минимальная единица, которой оперирует алгоритм - байт. Байт - это число от 0 до 255 включительно. Байт представляется с помощью восьми битов. Биты принимают значение 0 или 1. Далее будем считать, что каждый байт представляется в виде: a = a7a6a5a4a3a2a1a0.

· Операция сложения (a+b)

a + b = a xor b

· Умножение aна ‘x’

Это сдвиг aв лево на один бит.

· Умножение a на b

a = {3c}, b = {a1}:

b = {a1} = 10100001 = a•x•x•x•x•x•x•x + a•x•x•x•x•x + a

· У любого байта b, кроме нуля, есть обратный байт a= b-1,который обладает свойством a•b = {01}

Описание шифрования

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

· ExpandKey — Вычисление раундных ключей для всех раундов.

· SubBytes — Подстановка байтов с помощью таблицы подстановок;

· ShiftRows — Циклический сдвиг строк в форме на различные величины;

· MixColumns — Смешивание данных внутри каждого столбца формы;

· AddRoundKey — Сложение ключа раунда с формой. Порядок выполнения процедур 2 и 3 можно поменять местами в силу опеределения этих операций. Процедуры 4 и 5 тоже можно выполнять в разном порядке, но при этом изменяется количество их вызовов, поскольку MixColumns(AddRoundKey(A, B)) AddRoundKey(MixColumns(A),MixColumns(B)).

Шифрование производится по алгоритму, приведенному на Риc. 1.4.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.4 Блок-схема алгоритма шифрования.

1.Преобразование SubBytes

Преобразование SubBytes заключается в замене каждого байта {xy} формы (где x и y обозначают шестнадцатиричные цифры) на другой в соответствии сS-Box таблицей.

2.Преобразование ShiftRows

Преобразование ShiftRows заключается в циклическом сдвиге влево строк формы. Преобразование схематично представлено на Риc. 1.5. Первая строка остается неизменной. Во второй производится сдвиг на 1 байт, то есть первый байт переносится в конец. В третьей ― сдвиг на 2 байта, в четвертой ― на 3.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.5. Преобразование ShiftRows

3.Преобразование MixColumns

Преобразование MixColumns заключается в умножении квадратной матрицы 4-го порядка на каждый столбец формы (Рис. 1.6):

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.6 Преобразование MixColumns

Умножение производится в поле Галуа GF(28). Над каждым столбцом операция производится отдельно, как показано на Риc. 1.7.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис 1.7. Преобразование MixColumns

4. Преобразование AddRoundKey

В преобразовании AddRoundKey 32-битные слова раундного ключа прибавляются к столбцам формы с помощью побитовой операции XOR:

Понятия, необходимые для описания алгоритма AES - student2.ru

Здесь wi ― это столбцы ключа. Над каждым столбцом операция производится отдельно, как показано на Риc. 1.8.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.8. Преобразование AddRoundKey

5. Получение расписания раундовых ключей ExpandKey

В алгоритме AES генерируются раундовые ключи на основе ключа шифрования с помощью процедуры ExpandKey. Процедура ExpandKey создает Nb * (Nr + 1) слов: алгоритму требуется начальный ключ размером Nb, плюс каждый из Nr раундов требует ключ из Nb слов. Ниже приведен псевдокод процедуры:

ExpandKey(byte key[4 * Nk], word w[Nb * (Nr+1)],int Nk)

begin

word temp

i = 0;

while(i < Nk)

w[i] = word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3])

i = i + 1

end while

i = Nk

while(i < Nb * (Nr+1))

temp = w[i - 1]

if (i mod Nk = 0)

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

else if (Nk > 6 and i mod Nk = 4)

temp = SubWord(temp)

end if

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

i = i + 1

endwhile

end

Здесь использованы следующие функции:

-SubWord осуществляет замену каждого байта в слове в соответствии с таблицей подстановок S-box.

-RotWord осуществляет циклический сдвиг байтов в слове влево, как показано на Риc. 1.9.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.9. Процедура RotWord

Rcon(i) формирует слово [02i−1 , 00, 00, 00]

Описание дешифрования

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

· InvSubBytes ― Подстановка байтов с помощью обратной таблицы подстановок;

· InvShiftRows ― Циклический сдвиг строк в форме на различные величины;

· InvMixColumns ― Смешивание данных внутри каждого столбца формы;

Блок-схема алгоритма дешифрования приведена на рисунке 1.10.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.10 Блок-схема алгоритма дешифрования.

Процедуры ExpandKey и AddRoundKey остаются неизменными. Ключи раунда используются в обратном порядке.

1. Преобразование InvShiftRows

Это преобразование обратно преобразованию ShiftRows. Первая строка формы остается неизменной. Вторая строка циклически сдвигается вправо на 1 байт. Третья ― на 2, четвертая ― на 3. Схематично преобразование показано на Риc. 1.11.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.11 ПреобразованиеInvShiftRows

2. Преобразование InvSubBytes

Это преобразование обратно преобразованию SubBytes. Подстановка байтов происходит аналогично с помощью обратной таблицы подстановок.

3. Преобразование InvMixColumns

Это преобразование обратно преобразованию MixColumns. InvMixColumns преобразует в форме каждый столбец отдельно. Преобразование происходит по следующей формуле(Рис. 1.12):

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.12 Преобразование InvMixColumns

Здесь умножение также производится в поле Галуа GF(28 ).

Режим применения

Режим ECB (Electronic Codebook) В режиме ECB каждый блок шифруется независимо от других, как показано на Риc. 1.13. Таким образом, одинаковые блоки открытого текста преобразуются в одинаковые блоки зашифрованного текста.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 1.13. Режим ECB

Дешифрование происходит по аналогичной схеме. В режиме ECB можно производить шифрование и дешифрование нескольких блоков параллельно.

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

Проектирование программы

Для разработки приложения использованы язык C, библиотеки классов графического интерфейса WPF и среда разработки Visual Studio 2015.

Интерфейс

Весь основной функционал программы реализован в главном окне, изображенном на Рис. 2.1.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 2.1. Главное окно программы

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

Так же в программе присутствует окно настройки минимальной длины и сложности парольной фразы, оно показано на Рис. 2.2.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 2.2. Окно наложения ограничений на парольную фразу

Доступны следующие ограничения, накладываемые на парольную фразу:

· Требование о наличии хотя бы одной цифры

· Требование о наличии хотя бы одной буквы верхнего регистра

· Требование о наличии хотя бы одной буквы нижнего регистра

· Требование о наличии хоть одного специального символа (знаки препинания, арифметических операций и т.п.)

Информацию об авторе и назначении программы можно посмотреть в окне “Aboutprogram”, представленном на Рис. 2.3.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 2.3. Окно, содержащее информацию о программе

Для оповещения пользователя о событиях и ошибках при работе с программой были использованы диалоговые окна (класс System.Windows.MessageBox). Данные окна изображены на Рис. 2.4. , Рис.2.5 и Рис. 2.6.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 2.4. Диалоговое окно, сообщающее о некорректности ввода парольной фразы для шифрования сообщения/файла.

Понятия, необходимые для описания алгоритма AES - student2.ru

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

Понятия, необходимые для описания алгоритма AES - student2.ru

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

При открытии файлов для шифрования и дешифрования, а так же для сохранения шифротекста в текстовый файл предназначены специальные диалоговые окна(классы Microsoft.Win32.OpenFileDialog и Microsoft.Win32.SaveFileDialog). Эти окна изображены на рисунках 2.7 и 2.8.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 2.7. Диалоговое окно открытия файла.

Понятия, необходимые для описания алгоритма AES - student2.ru

Рис. 2.8. Диалоговое окно сохранения файла.

Тестирование программы

Проверим возможности программы.

Заключение

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

Приложение

Класс AES.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows;

using System.Threading;

using System.Text;

using System.Threading.Tasks;

using System.Security.Cryptography;

namespace AESProject

{

class AES

{

//режимAES(ключ: 128,192,256 бит)

public enum aesSubtype

{

shortKey = 128,

mediumKey = 192,

longKey = 256

};

//шифрованиевходногооткрытогоблока

public byte[] EncryptBlock(byte[] block, byte[] key, aesSubtype keyDimension)

{

int Nk, Nb, Nr;

Nk = (int)keyDimension / 32;

Nb = 4;

Nr = Nk + Nb + 2;

byte[][] state = new byte[4][];

byte[][] w = KeyExpansion(key, Nk, Nb, Nr);

//заполнение формы(состояния блока)

for (int i = 0; i < 4; i++)

{

byte[] column = new byte[4];

column[0] = block[i * 4];

column[1] = block[i * 4 + 1];

column[2] = block[i * 4 + 2];

column[3] = block[i * 4 + 3];

state[i] = column;

}

state = AddRoundKey(new byte[][] { w[0], w[1], w[2], w[3] }, state);

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

{

state = SubBytes(state);

state = ShiftRows(state);

if (round == Nr)

{

state = AddRoundKey(new byte[][] { w[round * 4], w[round * 4 + 1], w[round * 4 + 2], w[round * 4 + 3] }, state);

}

else

{

state = MixColumns(state);

state = AddRoundKey(new byte[][] { w[round * 4], w[round * 4 + 1], w[round * 4 + 2], w[round * 4 + 3] }, state);

}

}

byte[] cipherBlock = new byte[16];

for (int i = 0; i < 4; i++)

{

cipherBlock[i * 4] = state[i][0];

cipherBlock[i * 4 + 1] = state[i][1];

cipherBlock[i * 4 + 2] = state[i][2];

cipherBlock[i * 4 + 3] = state[i][3];

}

return cipherBlock;

}

//расшифровывание входного закрытого блока

public byte[] DecryptBlock(byte[] block, byte[] key, aesSubtype keyDimension)

{

int Nk, Nb, Nr;

Nk = (int)keyDimension / 32;

Nb = 4;

Nr = Nk + Nb + 2;

byte[][] state = new byte[4][];

byte[][] w = KeyExpansion(key, Nk, Nb, Nr);

//расположение раундовых ключей в обратном порядке

byte[][] rW = new byte[Nb * (Nr + 1)][];

for (int i = 0; i < Nr + 1; i++)

{

rW[Nb * (Nr + 1) - 1 - (i * 4) - 3] = w[i * 4];

rW[Nb * (Nr + 1) - 1 - (i * 4) - 2] = w[i * 4 + 1];

rW[Nb * (Nr + 1) - 1 - (i * 4) - 1] = w[i * 4 + 2];

rW[Nb * (Nr + 1) - 1 - (i * 4)] = w[i * 4 + 3];

}

w = rW;

//заполнение формы(состояния блока)

for (inti = 0; i< 4; i++)

{

byte[] column = new byte[4];

column[0] = block[i * 4];

column[1] = block[i * 4 + 1];

column[2] = block[i * 4 + 2];

column[3] = block[i * 4 + 3];

state[i] = column;

}

state = AddRoundKey(new byte[][] { w[0], w[1], w[2], w[3] }, state);

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

{

state = InvShiftRows(state);

state = InvSubBytes(state);

if (round == Nr)

{

state = AddRoundKey(new byte[][] { w[round * 4], w[round * 4 + 1], w[round * 4 + 2], w[round * 4 + 3] }, state);

}

else

{

state = AddRoundKey(new byte[][] { w[round * 4], w[round * 4 + 1], w[round * 4 + 2], w[round * 4 + 3] }, state);

state = InvMixColumns(state);

}

}

byte[] openBlock = new byte[16];

for (int i = 0; i < 4; i++)

{

openBlock[i * 4] = state[i][0];

openBlock[i * 4 + 1] = state[i][1];

openBlock[i * 4 + 2] = state[i][2];

openBlock[i * 4 + 3] = state[i][3];

}

returnopenBlock;

}

//получениешифротекстаизоткрытоготекста

public byte[] Encrypt(byte[] openText, string password, aesSubtype keyDimension)

{

byte[] key = PassToKey(password, keyDimension);

//добавление в начало текста сиганутры (строка "AES")

openText = (StrToBytes("AES").Concat(openText)).ToArray();

List<byte[]> openBlocksList = ByteArrToByteBlocksList(openText);

List<byte[]> cipherBlocksList = new List<byte[]>();

//в конце списка открытых блоков добавит еще один блок, в котором записана строка,

//означающаая количество байтов в исходном открытом тексте

int l = openText.Length;

string lStr = Convert.ToString(l);

List<byte> endBlockBytesLst = StrToBytes(lStr).ToList();

int cnt = endBlockBytesLst.Count;

for (int i = 0; i < 16 - cnt; i++)

{

endBlockBytesLst.Insert(0, Convert.ToByte('x'));

}

openBlocksList.Add(endBlockBytesLst.ToArray());

//-----------------------

int j = 0;

foreach (byte[] block in openBlocksList)

{

cipherBlocksList.Add(EncryptBlock(block, key, keyDimension));

j++;

}

return ByteBlocksListToByteArr(cipherBlocksList);

}

//получениеоткрытоготекстаизшифротекста

public byte[] Decrypt(byte[] cipherText, string password, aesSubtype keyDimension)

{

byte[] key = PassToKey(password, keyDimension);

List<byte[]> cipherBlocksList = ByteArrToByteBlocksList(cipherText);

List<byte[]> openBlocksList = new List<byte[]>();

foreach (byte[] block in cipherBlocksList)

{

openBlocksList.Add(DecryptBlock(block, key, keyDimension));

}

byte[] openBytes = ByteBlocksListToByteArr(openBlocksList);

//проверканаличиясигнатурывначалеоткрытоготекста

if (BytesToStr(openBytes.Take(3).ToArray()) != "AES")

return null;

//обрезание полученного открытого текста до длинны исходного открытого текста

string lstBlockStr = BytesToStr(openBlocksList[openBlocksList.Count - 1]);

int byteN = Convert.ToInt32(lstBlockStr.Substring(lstBlockStr.LastIndexOf("x") + 1));

openBytes = openBytes.Take(byteN).ToArray();

//изъятиебайтовсигнатуры

openBytes = openBytes.Skip(3).ToArray();

return openBytes;

}

//Замена байтов формы с помощью прямой таблицы подстановок

byte[][] SubBytes(byte[][] state)

{

GaluaFunctions gfInstance = new GaluaFunctions();

for (int i = 0; i < 4; i++)

for (int j = 0; j < 4; j++)

{

state[i][j] = gfInstance.SubByte(state[i][j]);

}

return state;

}

//Замена байтов формы с помощью обратной таблицы подстановок

byte[][] InvSubBytes(byte[][] state)

{

GaluaFunctions gfInstance = new GaluaFunctions();

for (int i = 0; i < 4; i++)

for (int j = 0; j < 4; j++)

{

state[i][j] = gfInstance.InvSubByte(state[i][j]);

}

return state;

}

//Прибавление раундового ключа к форме

byte[][] AddRoundKey(byte[][] roundKey, byte[][] state)

{

GaluaFunctions gfInstance = new GaluaFunctions();

for (int i = 0; i < 4; i++)

for (int j = 0; j < 4; j++)

{

state[i][j] = gfInstance.Sum(state[i][j], roundKey[i][j]);

}

return state;

}

//перемешиваниестолбцовформы

byte[][] MixColumns(byte[][] state)

{

for (int i = 0; i < 4; i++)

state[i] = ColumnConverting(state[i]);

return state;

}

byte[][] InvMixColumns(byte[][] state)

{

for (int i = 0; i < 4; i++)

state[i] = InvColumnConverting(state[i]);

return state;

}

//Умножение специфической матрицы на столбец

byte[] ColumnConverting(byte[] column)

{

byte[] newColumn = new byte[4];

byte[,] SpecMatrix = {

{0x02, 0x03, 0x01, 0x01},

{0x01, 0x02, 0x03, 0x01},

{0x01, 0x01, 0x02, 0x03},

{0x03, 0x01, 0x01, 0x02}

};

GaluaFunctions gFInstance = new GaluaFunctions();

for (int i = 0; i < 4; i++)

{

newColumn[i] = gFInstance.Sum((gFInstance.Sum((gFInstance.Sum(gFInstance.Mul(SpecMatrix[i, 0], column[0]), gFInstance.Mul(SpecMatrix[i, 1], column[1]))), gFInstance.Mul(SpecMatrix[i, 2], column[2]))), gFInstance.Mul(SpecMatrix[i, 3], column[3]));

}

return newColumn;

}

byte[] InvColumnConverting(byte[] column)

{

byte[] newColumn = new byte[4];

byte[,] SpecMatrix = {

{0x0e, 0x0b, 0x0d, 0x09},

{0x09, 0x0e, 0x0b, 0x0d},

{0x0d, 0x09, 0x0e, 0x0b},

{0x0b, 0x0d, 0x09, 0x0e}

};

GaluaFunctions gFInstance = new GaluaFunctions();

for (int i = 0; i < 4; i++)

{

newColumn[i] = gFInstance.Sum((gFInstance.Sum((gFInstance.Sum(gFInstance.Mul(SpecMatrix[i, 0], column[0]), gFInstance.Mul(SpecMatrix[i, 1], column[1]))), gFInstance.Mul(SpecMatrix[i, 2], column[2]))), gFInstance.Mul(SpecMatrix[i, 3], column[3]));

}

return newColumn;

}

//ступенчатыйциклическийсдвигстрокформывлево

byte[][] ShiftRows(byte[][] state)

{

state = ShiftNRow(1, 1, state);

state = ShiftNRow(2, 2, state);

state = ShiftNRow(3, 3, state);

return state;

}

//ступенчатый циклический сдвиг строк формы вправо

byte[][] InvShiftRows(byte[][] state)

{

state = InvShiftNRow(1, 1, state);

state = InvShiftNRow(2, 2, state);

state = InvShiftNRow(3, 3, state);

return state;

}

byte[][] ShiftNRow(int rowN, int n, byte[][] state)

{

if (n == 0) return state;

byte tmp = state[0][rowN];

for (int i = 0; i < 3; i++)

{

state[i][rowN] = state[i + 1][rowN];

}

state[3][rowN] = tmp;

return ShiftNRow(rowN, n - 1, state);

}

byte[][] InvShiftNRow(int rowN, int n, byte[][] state)

{

if (n == 0) return state;

byte tmp = state[3][rowN];

for (int i = 3; i > 0; i--)

{

state[i][rowN] = state[i - 1][rowN];

}

state[0][rowN] = tmp;

return InvShiftNRow(rowN, n - 1, state);

}

//получение расписания ключей из исходного ключа

public byte[][] KeyExpansion(byte[] key, int Nk, int Nb, int Nr)

{

//--------------------

string[] rconLog = new string[Nr];

string[] rotWordLog = new string[Nr];

string[] subWLog = new string[Nr];

string[] xorRcon = new string[Nr];

//--------------------

byte[][] w = new byte[Nb * (Nr + 1)][];

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

{

byte[] arr = { key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3] };

w[i] = arr;

}

byte[] temp;

GaluaFunctions gFInstance = new GaluaFunctions();

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

{

temp = new byte[] { w[i - 1][0], w[i - 1][1], w[i - 1][2], w[i - 1][3] };

if (i % Nk == 0)

{

byte[] rCon = Rcon(i / Nk);

rconLog[i / Nk - 1] = BitConverter.ToString(rCon);

temp = RotWord(temp, 1);

rotWordLog[i / Nk - 1] = BitConverter.ToString(temp);

temp = SubWord(temp);

subWLog[i / Nk - 1] = BitConverter.ToString(temp);

temp[0] = gFInstance.Xor(temp[0], rCon[0]);

temp[1] = gFInstance.Xor(temp[1], rCon[1]);

temp[2] = gFInstance.Xor(temp[2], rCon[2]);

temp[3] = gFInstance.Xor(temp[3], rCon[3]);

xorRcon[i / Nk - 1] = BitConverter.ToString(temp);

}

else if (Nk > 6 && i % Nk == 4)

temp = SubWord(temp);

byte[] arr = { gFInstance.Xor(w[i - Nk][0], temp[0]), gFInstance.Xor(w[i - Nk][1], temp[1]), gFInstance.Xor(w[i - Nk][2], temp[2]), gFInstance.Xor(w[i - Nk][3], temp[3]) };

w[i] = arr;

}

//---------------------------

string[] keySchedule = new string[Nb * (Nr + 1)];

for (int i = 0; i < Nb * (Nr + 1); i++)

{

byte[] ar = w[i];

keySchedule[i] = BitConverter.ToString(ar);

}

//---------------------------

return w;

}

//замена байтов слова с помощью прямой таблицы подстанвоок

byte[] SubWord(byte[] word)

{

GaluaFunctions gFinstance = new GaluaFunctions();

for (int i = 0; i < word.Length; i++)

{

word[i] = gFinstance.SubByte(word[i]);

}

return word;

}

//циклический сдвиг слова в лево

byte[] RotWord(byte[] word, intn)

{

if (n == 0) return word;

byte tmp = 0;

for (int i = 0; i < word.Length - 1; i++)

{

if (i == 0)

{

tmp = word[word.Length - 1];

word[word.Length - 1] = word[0];

}

else

{

word[i - 1] = word[i];

}

}

word[word.Length - 2] = tmp;

return RotWord(word, n - 1);

}

byte[] Rcon(int i)

{

byte[] word = { 01, 0, 0, 0 };

if (i <= 1)

return word;

if (i == 2)

{

word[0] = 0x02;

return word;

}

GaluaFunctions gFinstance = new GaluaFunctions();

byte x = 0x02;

for (int k = 2; k <= i - 1; k++)

{

x = gFinstance.Mul(x, 0x02);

}

word[0] = x;

return word;

}

//преобразование строки в массив байтов

public byte[] StrToBytes(string inpString)

{

return Encoding.UTF8.GetBytes(inpString);

}

//преобразованиемассивабайтоввстроку

public string BytesToStr(byte[] inpBytes)

{

return new string(Encoding.UTF8.GetChars(inpBytes));

}

//разбиение массива байтов на список байтблоков фикс.длинны. (длиннаблока = 128 бит = 16 байт)

List<byte[]> ByteArrToByteBlocksList(byte[] openText)

{

/* int l = openText.Length;

string lStr = Convert.ToString(l);

List<byte> endBlockBytesLst = StrToBytes(lStr).ToList();

int cnt = endBlockBytesLst.Count;

for (int i =0; i<16-cnt; i++)

{

endBlockBytesLst.Insert(0, Convert.ToByte('x'));

}*/

List<byte[]> blocksList = new List<byte[]>((int)Math.Ceiling((decimal)(openText.Length / 16F)));

while (openText != null)

{

if (openText.Length >= 16)

{

if (openText.Length == 16)

{

blocksList.Add(openText.Take(16).ToArray());

return blocksList;

}

blocksList.Add(openText.Take(16).ToArray());

openText = openText.Skip(16).ToArray();

}

else

{

byte[] newBlock = new byte[16];

for (int i = 0; i < 16; i++)

{

newBlock[i] = (i < openText.Length ? openText[i] : (byte)'x');

}

blocksList.Add(newBlock);

openText = null;

}

}

// blocksList.Add(endBlockBytesLst.ToArray());

return blocksList;

}

//слияние списка байтблоков в массив байтов

byte[] ByteBlocksListToByteArr(List<byte[]> blocksList)

{

List<byte> byteArr = new List<byte>();

foreach (byte[] block in blocksList)

foreach (byte bt in block)

{

byteArr.Add(bt);

}

return byteArr.ToArray();

}

//(построение ключа)хэширование пароля в зависимости от выбранной длинны ключа (128/192/256)

public byte[] PassToKey(string password, aesSubtype keyDimension)

{

byte[] key = Encoding.UTF8.GetBytes(password);

byte[] keyHash = null;

switch (keyDimension)

{

case aesSubtype.shortKey:

keyHash = MD5.Create().ComputeHash(key);

break;

case aesSubtype.mediumKey:

keyHash = SHA256.Create().ComputeHash(key);

keyHash = keyHash.Take(24).ToArray();

break;

case aesSubtype.longKey:

keyHash = SHA256.Create().ComputeHash(key);

break;

}

return keyHash;

}

}

}

КлассGF.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace AESProject

{

//классалгебрыГалуаполя 2^8

class GaluaFunctions

{

//суммированиедвухмногочленов

public byte Sum (byte a, byte b)

{

return Convert.ToByte(Convert.ToInt32(a)^Convert.ToInt32(b));

}

public byte Xor(byte a, byte b)

{

return Convert.ToByte(Convert.ToInt32(a) ^ Convert.ToInt32(b));

}

//умножение многочлена на многочлен 0x02

byte XMul(byte a)

{

var highbit = a & 0x80;

var shl = (a << 1) & 0xff;

return Convert.ToByte(highbit == 0 ? shl : shl ^ 0x1b);

}

//n-кратное умножение многочлена a на многочлен 0x02

public byte NXMul(byte a,int n)

{

if (n > 0)

{

var highbit = a & 0x80;

var shl = (a << 1) & 0xff;

return NXMul(Convert.ToByte(highbit == 0 ? shl : shl ^ 0x1b),n-1);

}

else return a;

}

//умножение многочлена a на многочлен b

public byte Mul(byte a, byte b)

{

byte res = 0x00;

List<int> binBList = DecToBin(b);

for (int i = 0; i < 8; i++)

{

if (binBList[i] == 1) res = Sum(res, NXMul(a, i));

}

return res;

}

public List<int> DecToBin(int decNum)

{

List<int> result = new List<int>();

while (decNum >= 2)

{

int rest = decNum % 2;

decNum = (int)(decNum / 2);

result.Add(rest);

}

result.Add(decNum);

result.Reverse();

if (result.Count < 8)

{

int rC = result.Count;

for(int i = 0; i< 8 - rC;i++) {

result.Insert(0, 0);

}

}

result.Reverse();

return result;

}

//нахождение обратного многочлена

byte getInverseByte(byte a)

{

if (a == 0) return a;

for (byte b = byte.MinValue; b <= byte.MaxValue; b += 1)

if (Mul(b, a) == 0x01) return b;

return a;

}

//таблицы прямой и боратной подстановки(для AES)

public byte SubByte(byte b)

{

byte[,] sbox = {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

};

string hexStr = Convert.ToString(b, 16);

int i1;

int i2;

if (hexStr.Length == 2)

{

i1 = Convert.ToInt32(hexStr[0].ToString(), 16);

i2 = Convert.ToInt32(hexStr[1].ToString(), 16);

}

else

{

i1 = 0;

i2 = Convert.ToInt32(hexStr[0].ToString(), 16);

}

return sbox[i1, i2];

}

public byte InvSubByte(byte b)

{

byte[,] sbox = {

{0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb},

{0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb},

{0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e},

{0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25},

{0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92},

{0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84},

{0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06},

{0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b},

{0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73},

{0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e},

{0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b},

{0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4},

{0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f},

{0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef},

{0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61},

{0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}

};

string hexStr = Convert.ToString(b, 16);

int i1;

int i2;

if (hexStr.Length == 2)

{

i1 = Convert.ToInt32(hexStr[0].ToString(), 16);

i2 = Convert.ToInt32(hexStr[1].ToString(), 16);

}

else

{

i1 = 0;

i2 = Convert.ToInt32(hexStr[0].ToString(), 16);

}

return sbox[i1, i2];

}

}

}

Классглавногоокна

using System;

using System.Collections.Generic;

using System.Linq;

using System.IO;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.Windows.Threading;

using Microsoft.Win32;

namespace AESProject

{

/// <summary>

/// Логикавзаимодействиядля MainWindow.xaml

/// </summary>

public partial class MainWindow : Window

{

System.Windows.Threading.DispatcherTimer timer;

AES aesInstance;

AES.aesSubtype encrMode = AES.aesSubtype.shortKey;

AES.aesSubtype decrMode = AES.aesSubtype.shortKey;

AES.aesSubtype encrFMode = AES.aesSubtype.shortKey;

AES.aesSubtype decrFMode = AES.aesSubtype.shortKey;

byte[] encryptedMsg=null;

byte[] decryptedMsg;

PassPhrConstr passPhrConstrInstance;

List<Action> listToDo = new List<Action>();

float blockEncrProgress;

string encryptingFileName;

int encrBlockI = 0;

int encrBlockTotal = 0;

float blockDecrProgress;

string decryptingFileName;

int decrBlockI = 0;

int decrBlockTotal = 0;

public MainWindow()

{

timer = new System.Windows.Threading.DispatcherTimer();

timer.Tick += new EventHandler(timerTick);

timer.Interval = new TimeSpan(0, 0, 0,0,100);

InitializeComponent();

passPhrConstrInstance = new PassPhrConstr();

aesInstance = new AES();

timer.Start();

}

void ThreadingFileEncryption (object inpInfo)

{

CryptoInfo newInst = (CryptoInfo)inpInfo;

StreamFileEncrypt(newInst.inpFileName, newInst.outFileName, newInst.key, newInst.cryptoMode);

}

void ThreadingFileDecryption (object inpInfo)

{

CryptoInfo newInst = (CryptoInfo)inpInfo;

StreamFileDecrypt(newInst.inpFileName, newInst.outFileName, newInst.key, newInst.cryptoMode);

}

private void timerTick(object sender, EventArgs e)

{

while (listToDo.Count > 0)

{

Action someFunc = listToDo[0];

listToDo.RemoveAt(0);

try { someFunc.Invoke(); }

catch { }

}

}

private void radioButton2_Click(object sender, RoutedEventArgs e)

{

encrMode = AES.aesSubtype.longKey;

keyTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(encr1PasswordBox.Password, encrMode)).Replace("-", "");

}

private void radioButton1_Click(object sender, RoutedEventArgs e)

{

encrMode = AES.aesSubtype.mediumKey;

keyTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(encr1PasswordBox.Password, encrMode)).Replace("-", "");

}

private void radioButton_Click(object sender, RoutedEventArgs e)

{

encrMode = AES.aesSubtype.shortKey;

keyTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(encr1PasswordBox.Password, encrMode)).Replace("-", "");

}

private void encryptMsgButton_Click(object sender, RoutedEventArgs e)

{

if (encr1PasswordBox.Password != "" && encr1PasswordBox.Password == encr2PasswordBox.Password)

{

if (!passPhrConstrInstance.CheckStringForCorrectness(encr1PasswordBox.Password))

{

MessageBox.Show("The passphrase does not satisfy the constraints");

return;

}

encryptedMsg = aesInstance.Encrypt(aesInstance.StrToBytes(msgTextBox.Text), encr1PasswordBox.Password, encrMode);

cipherTextBlock.Text = aesInstance.BytesToStr(encryptedMsg);

cipherHexTextBlock.Text = BitConverter.ToString(encryptedMsg).Replace("-", ".");

saveCipherButton.IsEnabled = true;

}else

{

MessageBox.Show("Passphrases should not be empty.\nPassphrases must match.");

}

}

private void radioButton3_Click(object sender, RoutedEventArgs e)

{

decrMode = AES.aesSubtype.shortKey;

keyDecrTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(decrPasswordBox.Password, decrMode)).Replace("-", "");

}

private void radioButton4_Click(object sender, RoutedEventArgs e)

{

decrMode = AES.aesSubtype.mediumKey;

keyDecrTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(decrPasswordBox.Password, decrMode)).Replace("-", "");

}

private void radioButton5_Click(object sender, RoutedEventArgs e)

{

decrMode = AES.aesSubtype.longKey;

keyDecrTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(decrPasswordBox.Password, decrMode)).Replace("-", "");

}

private void decryptMsgButton_Click(object sender, RoutedEventArgs e)

{

if (encryptedMsg != null)

{

decryptedMsg = aesInstance.Decrypt(encryptedMsg, decrPasswordBox.Password, decrMode);

if (decryptedMsg != null)

openTextBlock.Text = aesInstance.BytesToStr(decryptedMsg);

else

MessageBox.Show("Invalid passphrase.");

}

else MessageBox.Show("Encrypt message before.");

}

private void encrFileButton_Click(object sender, RoutedEventArgs e)

{

OpenFileDialog openFileDialog = new OpenFileDialog();

Nullable<bool> result = openFileDialog.ShowDialog();

AES aESInstance = new AES();

if (result == true)

{

if (fileEncrPasswordBox1.Password != "" && fileEncrPasswordBox1.Password == fileEncrPasswordBox2.Password)

{

if (!passPhrConstrInstance.CheckStringForCorrectness(fileEncrPasswordBox1.Password))

{

MessageBox.Show("The passphrase does not satisfy the constraints");

return;

}

string filename = openFileDialog.FileName;

encryptingFileName = filename.Insert(filename.LastIndexOf('.'), "ENCR");

CryptoInfo cryptoInfoInstance = new CryptoInfo(filename, filename.Insert(filename.LastIndexOf('.'), "ENCR"), aesInstance.PassToKey(fileEncrPasswordBox1.Password, encrFMode), encrFMode);

Stream sourceFStr = File.OpenRead(filename);

blockEncrProgress = 100F/( sourceFStr.Length / 16F);

encrBlockTotal = (int)(Math.Round(sourceFStr.Length / 16F));

Thread newEncrThread = new Thread(new ParameterizedThreadStart(ThreadingFileEncryption));

newEncrThread.Start(cryptoInfoInstance);

}

else MessageBox.Show("Passphrases should not be empty.\nPassphrases must match.");

}

else

encrFileInfoTextBlock.Text = "An error occurred when opening the file. Try again.";

}

private void decrFileButton_Click(object sender, RoutedEventArgs e)

{

OpenFileDialog openFileDialog = new OpenFileDialog();

Nullable<bool> result = openFileDialog.ShowDialog();

if (result == true)

{

if (fileDecrPasswordBox.Password != "")

{

string filename = openFileDialog.FileName;

decryptingFileName = filename.Insert(filename.LastIndexOf('.'), "DECR");

CryptoInfo cryptoInfoInstance = new CryptoInfo(filename, filename.Insert(filename.LastIndexOf('.'), "DECR"), aesInstance.PassToKey(fileDecrPasswordBox.Password, decrFMode), decrFMode);

Stream sourceFStr = File.OpenRead(filename);

blockDecrProgress = 100F / (sourceFStr.Length / 16F);

decrBlockTotal = (int)(Math.Round(sourceFStr.Length / 16F));

Thread newDecrThread = new Thread(new ParameterizedThreadStart(ThreadingFileDecryption));

newDecrThread.Start(cryptoInfoInstance);

}

else MessageBox.Show("Passphrase should not be empty.");

}

else

decrFileInfoTextBlock.Text = "An error occurred when opening the file. Try again.";

}

void StreamFileEncrypt(string inputFileName, string encrFileName, byte[] key, AES.aesSubtype encrMode)

{

Stream dest = File.OpenWrite(encrFileName);

AES aESInstance = new AES();

byte[] signBlock;

signBlock = aESInstance.StrToBytes("AESxxxxxxxxxxxxx");

signBlock = aesInstance.EncryptBlock(signBlock, key, encrMode);

dest.Write(signBlock, 0, 16);

using (Stream source = File.OpenRead(inputFileName))

{

listToDo.Add(new Action(() =>

{

encrFileButton.IsEnabled = false;

encrFileInfoTextBlock.Text = "Encryption in procces. Please stand by.";

}));

byte[] buffer = new byte[16];

int bytesRead;

long blockI = 0;

long totalBlocks = source.Length / 16;

while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)

{

if (bytesRead < 16)

{

byte[] tail = new byte[16 - bytesRead];

for (int i = 0; i < 16 - bytesRead; i++)

tail[i] = Convert.ToByte('x');

buffer = (buffer.Take(bytesRead).Concat(tail)).ToArray();

byte[] encrBlock = aesInstance.EncryptBlock(buffer, key, encrMode);

dest.Write(encrBlock, 0, 16);

}

else

{

byte[] encrBlock = aesInstance.EncryptBlock(buffer, key, encrMode);

dest.Write(encrBlock, 0, bytesRead);

}

blockI++;

listToDo.Add(new Action(() =>

{

this.encrProgressBar.Value += blockEncrProgress;

encrBlockI++;

this.encrProgressTextBlock.Text = encrBlockI + " / "+encrBlockTotal + " blocks encrypted";

}));

}

source.Close();

}

dest.Close();

listToDo.Add(new Action(()=>

{

encrProgressTextBlock.Text = "";

encrBlockI = 0;

this.encrProgressBar.Value = 0;

if (encrDelFileCheckBox.IsChecked == true) File.Delete(inputFileName);

encrFileInfoTextBlock.Text = "Encrypted file has been saved as " + encryptingFileName;

encrFileButton.IsEnabled = true;

}));

}

void StreamFileDecrypt(string inputFileName, string decrFileName, byte[] key, AES.aesSubtype decrMode)

{

Stream dest = File.OpenWrite(decrFileName);

AES aESInstance = new AES();

using (Stream source = File.OpenRead(inputFileName))

{

listToDo.Add(new Action(() =>

{

decrFileButton.IsEnabled = false;

decrFileInfoTextBlock.Text = "Decryption in procces. Please stand by.";

}));

byte[] buffer = new byte[16];

int bytesRead;

long blockI=0;

long totalBlocks = source.Length / 16;

while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)

{

byte[] decrBlock = aesInstance.DecryptBlock(buffer, key, decrMode);

if (blockI == totalBlocks - 1)

{

string blockStr = aesInstance.BytesToStr(decrBlock);

int xPos = blockStr.IndexOf('x');

if (xPos >= 0)

{

decrBlock = decrBlock.Take(xPos).ToArray();

bytesRead = xPos;

}

}

if(blockI == 0)

{

if(aESInstance.BytesToStr(decrBlock.Take(3).ToArray()) != "AES")

{

dest.Close();

File.Delete(decrFileName);

MessageBox.Show("Invalid passphrase.");

listToDo.Add(new Action(() =>

{

decrFileInfoTextBlock.Text = "Decryption procces was interrupted";

decrFileButton.IsEnabled = true;

}));

return;

// break;

}else

{

blockI++;

continue;

}

}

dest.Write(decrBlock, 0, bytesRead);

blockI++;

listToDo.Add(new Action(() =>

{

this.decrProgressBar.Value += blockDecrProgress;

decrBlockI++;

this.decrProgressTextBlock.Text = decrBlockI + " / " + decrBlockTotal + " blocks decrypted";

}));

}

source.Close();

}

dest.Close();

listToDo.Add(new Action(() =>

{

decrProgressTextBlock.Text = "";

decrBlockI = 0;

this.decrProgressBar.Value = 0;

if (decrDelFileCheckBox.IsChecked == true) File.Delete(inputFileName);

decrFileInfoTextBlock.Text = "Decrypted file has been saved as " + decrFileName;

decrFileButton.IsEnabled = true;

}));

}

private void radioButton6_Click(object sender, RoutedEventArgs e)

{

encrFMode = AES.aesSubtype.shortKey;

}

private void radioButton7_Click(object sender, RoutedEventArgs e)

{

encrFMode = AES.aesSubtype.mediumKey;

}

private void radioButton8_Click(object sender, RoutedEventArgs e)

{

encrFMode = AES.aesSubtype.longKey;

}

private void radioButton9_Click(object sender, RoutedEventArgs e)

{

decrFMode = AES.aesSubtype.shortKey;

}

private void radioButton10_Click(object sender, RoutedEventArgs e)

{

decrFMode = AES.aesSubtype.mediumKey;

}

private void radioButton11_Click(object sender, RoutedEventArgs e)

{

decrFMode = AES.aesSubtype.longKey;

}

private void aboutMenuItem_Click(object sender, RoutedEventArgs e)

{

AboutWindow aboutWndInstance = new AboutWindow();

aboutWndInstance.Owner = this;

this.IsEnabled = false;

aboutWndInstance.Show();

}

private void shutDownMenuItem_Click(object sender, RoutedEventArgs e)

{

this.Close();

}

private void passwordBox_PasswordChanged(object sender, RoutedEventArgs e)

{

keyTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(encr1PasswordBox.Password, encrMode)).Replace("-", "");

}

private void passwordBox_PasswordChanged_1(object sender, RoutedEventArgs e)

{

keyDecrTextBlock.Text = BitConverter.ToString(aesInstance.PassToKey(decrPasswordBox.Password, decrMode)).Replace("-", "");

}

private void saveCipherButton_Click(object sender, RoutedEventArgs e)

{

SaveFileDialog saveFileDialog = new SaveFileDialog();

Nullable<bool> result = saveFileDialog.ShowDialog();

if (result == true)

{

string filename = saveFileDialog.FileName;

File.WriteAllBytes(filename, encryptedMsg);

}

}

private void passPhrConstrMenuItem_Click(object sender, RoutedEventArgs e)

{

PassPhraseConstraintsWindow newConstrWnd = new PassPhraseConstraintsWindow(passPhrConstrInstance);

newConstrWnd.Owner = this;

newConstrWnd.Show();

}

}

}

Введение

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

Описание алгоритма

Алгоритм AES- симметричный криптоалгоритмом блочного шифрования. Является упрощенным вариантом криптоалгоритма Rijndael.Размер блока шифрования фиксирован и составляет 128 бит, это и есть отличие AES от Rijndael, в последнем длина блока может варьироваться. Размер ключа может быть равным 128, 192, либо 256 бит.

Алгоритм преобра

Наши рекомендации