Зарегистрировано «___»_____20___г. ________ __________________________

advertisement
Зарегистрировано «___»_____20___г.
________ __________________________
Подпись
(расшифровка подписи)
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ АВТОНОМНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ
БЕЛГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ НАЦИОНАЛЬНЫЙ
ИССЛЕДОВАТЕЛЬСКИЙ УНИВЕРСИТЕТ
(НИУ «БелГУ»)
ФАКУЛЬТЕТ КОМПЬЮТЕРНЫХ НАУК И ТЕЛЕКОММУНИКАЦИЙ
КАФЕДРА МАТЕМАТИЧЕСКОГО ОБЕСПЕЧЕНИЯ И АДМИНИСТРИРОВАНИЯ
ВЫЧИСЛИТЕЛЬНЫХ СИСТЕМ
РАЗРАБОТКА ПРОГРАММЫ ШИФРОВАНИЯ
ФАЙЛОВ НА ОСНОВЕ АЛГОРИТМА RC2 В
РЕЖИМЕ ECB
Курсовая работа
студентки дневного отделения 4 курса группы 140901
Батищева Дениса Сергеевича
Научный руководитель:
доцент Румбешт В.В.
БЕЛГОРОД 2012
Содержание
Введение ........................................................................................................................ 3
1. Стандарт шифрования данных RC2 ..................................................................... 4
2. Режим простой замены ECB ................................................................................. 8
3. Разработка программной реализации алгоритма................................................ 9
Заключение.................................................................................................................. 22
Список использованных источников ....................................................................... 23
Приложение 1 ............................................................................................................. 24
3
Введение
Задача обеспечения конфиденциальности и защищенности информации
стояла всегда. В связи с ростом количества компьютеров и объемов
обрабатываемой ими информации были выделены методы преобразования
данных для сокрытия информации, названные криптографией.
Криптография в прошлом использовалась лишь в военных целях. Однако
сейчас, по мере образования информационного общества, криптография
становится
одним
из
основных
инструментов,
обеспечивающих
конфиденциальность, авторизацию, электронные платежи, корпоративную
безопасность и бесчисленное множество других важных вещей.
Основным инструментом криптографии для защиты данных является
шифрование.
Шифрование
можно
разделить
на
блочное
и
поточное,
симметричное и с открытым ключом.
В данной курсовой работе будет рассмотрен симметричный блочный
алгоритм шифрования RC2 в режиме ECB.
Результатом работы должна стать программная реализация данного
алгоритма.
Для правильного выполнения курсовой работы будут выполнены
следующие подзадачи:
 чтение и изучение документации по данному алгоритму
 изучения работы данного алгоритма в режиме ECB
 программная реализация алгоритма с учетом полученных знаний
Курсовая работа написана на 31 листе. Курсовая работа содержит 11
рисунков, и 5 листингов.
4
1. Стандарт шифрования данных RC2
RC2 — блочный шифр с переменной длиной ключа, разработанный Роном
Ривестом. Алгоритм является более быстрым, чем алгоритм DES. Стойкость
может быть больше или меньше чем у DES, в зависимости от длины ключа.
Данный алгоритм построен на сети фейстеля. Состоит из 16 раундов.
Оперирует блоками по 64 бита. Переменная длина ключа обеспечивает
различную криптостойкость, при этом следует учесть, что переменная длина
ключа, вводимого пользователем, сам же алгоритм работает с ключом
фиксированной длины – 128 байт, это позволяет не использовать дополнительно
алгоритмы хеширования для покрытия всей длины ключа значимыми битами.
Обладает переменной криптостойкостью. Например, при длине ключа в 128
байт, устойчивость аналогичная IDEA или тройному DES. Но, так как алгоритм
является собственностью RSA Security Inc., то ключи длиннее 40 байт за
пределами США использовать нельзя без лицензирования.
Алгоритм состоит из следующих операций:

Расширение ключа. Первая часть принимает входной ключ (переменной
длины) и возвращает созданный расширенный ключ, состоящий из 64
слов K[0], …, K[63].

Шифрование. Вторая часть принимает 64 бита входных данных, которые
хранятся в словах R[0], …, R[3], а затем происходит шифрование.

Расшифровка.
Последняя
часть
отвечает
за
операцию
обратную
шифрованию.
1.1 Key expansion или расширение ключа.
Key expansion или расширение ключа заключается в заполнении 128 байт
ключа на основе ключа пользователя. Именно эта операция позволяет
использовать
ключ
переменной
длины
без
использования
алгоритмов
хеширования для покрытия всей длины эффективного ключа ненулевыми
5
значениями. Для выполнения этой операции необходимо ввести переменные T1
– длина ключа, введенного пользователем, T8 - = (T1+7)/8, TM = 255 MOD 2^(8
+ T1 - 8*T8), а так же PITABLE – случайная таблица, используемая для
дополнения ключа на 128 байт.
Операция заключается в следующем:
Сначала вводится временный вектор L в 128 байт, в который с нулевой
позиции копируется ключ, введенный пользователем.
Далее выполняется следующая последовательность действий:
for i = T, T+1, ..., 127 do
L[i] = PITABLE[L[i-1] + L[i-T]];
L[128-T8] = PITABLE[L[128-T8] & TM];
for i = 127-T8, ..., 0 do
L[i] = PITABLE[L[i+1] XOR L[i+T8]];
То есть при расширении берут сумму первого и последнего байта ключа,
ищут сумму (mod 256) в PITABLE-блоке и добавляют результат в ключ.
Операция повторяется со вторым и последним новым байтом пока ключ не
будет дополнен до 128 байт.
Стоит отметить, что эта операция не обязательна, при условии того, что
пользователь изначально ввел ключ длиной 128 и больше, что вряд ли может
быть.
1.2 Mix up или операция перемешивания при шифровании
В данной операции блок в 64 бита разбивается на 4 слова по 16 бит и далее
оперирует ими.
R[i] = R[i] + K[j] + (R[i-1] & R[i-2]) + ((˜R[i-1]) &
R[i-3]);
6
j = j + 1;
R[i] = R[i] << s[i];
Где R – наш блок открытого/закрытого текста, K – расширенный ключ и s –
массив значений { 1, 2, 3, 5 }.
1.3 Mash или операция объединения при шифровании
R[i] = R[i] + K[R[i-1] & 63];
Где R,K – те же переменные, что и в раунде Mix up.
Таким образом, операция шифрования в алгоритме RC2 выглядит следующим
образом:
1. Инициализация слов R[0], …, R[3] состоящих из входных 64-битных
значений.
2. Расширение ключа.
3. Инициализация j нулевым значением.
4. 5 циклов операции mix up
5. 1 цикл операции mash
6. 6 циклов операции mix up
7. 1 цикл операции mash
8. 5 циклов операции mix up
Расшифровка основывается так же на операция Mix up и Mash, только
замененных на противоположные. И так же состоит из:
1. Инициализация слов R[0], …, R[3] состоящих из входных 64-битных
значений шифротекста.
2. Расширение ключа.
3. Инициализация j = 63.
4. 5 циклов операции r-mix up
7
5. 1 цикл операции r-mash
6. 6 циклов операции r-mix up
7. 1 цикл операции r-mash
8. 5 циклов операции r-mix up
1.3 R-Mix up или операция перемешивания при расшифровке
R[i] = R[i] >> s[i];
R[i] = R[i] - K[j] - (R[i-1] & R[i-2]) - ((˜R[i-1]) &
R[i-3]);
j = j - 1;
1.4 R-Mash или операция объединения при расшифровке
R[i] = R[i] — K[R[i-1] & 63];
8
2. Режим простой замены ECB
Режим электронной кодовой книги (англ. Electronic Code book, ECB) —
один из вариантов использования симметричного блочного шифра, при котором
каждый блок открытого текста заменяется блоком шифртекста.
Шифруемый текст разбивается на блоки, при этом, каждый блок
шифруется отдельно, не взаимодействуя с другими блоками.
Шифрование может быть описано следующим образом:
Ci  Ek ( Pi ) , где i — номера блоков, Ci и Pi — блоки зашифрованного и
открытого текстов соответственно, а Ek — функция блочного шифрования.
Рис. 1. Шифрование в режиме ECB
Процесс расшифрования происходит аналогично:
Pi  Dk (Ci )
Рис. 2. Расшифрование в режиме ECB
9
3. Разработка программной реализации алгоритма
3.1. Создание Windows – приложения
Целью
программы
является
шифрование/расшифрование
файлов
алгоритмом RC2 в режиме ECB.
Исходя
из
цели,
программа
должна
обеспечивать
возможность
выполнения перечисленных ниже функций:
 функция открытия файла;
 функция шифрования;
 функция сохранения зашифрованного файла;
 функция расшифрования.
 функция сохранения расшифрованного файла
Входными данными являются пароль, из которого получается ключ и
который должен быть введен пользователем с клавиатуры. И любой файл,
который также выбирается пользователем.
Для удобства пользователя в качестве интерфейса выбрано приложение на
форме. Форма будет содержать 1 блок ввода теста для ключевой фразы
пользователя, 5 текстовых меток, отражающие названия элементов управления
приложением и 3 командные кнопки для управления приложением.
Выходными данными являются расшифрованный или зашифрованный
файл - в зависимости от того что выбрал пользователь.
Приложение должно адекватно реагировать на исключительные ситуации:
 Отсутствие файла для работы для шифровки/расшифровки
 Пустая ключевая фраза
3.2 Диаграмма прецедентов
На основании этого описания была сформирована диаграмма прецедентов,
отражающая взаимодействия пользователя и программы на базовом уровне.
Диаграмма представлена на рисунке 3.
10
Зашифровать
файл
Открыть
файл
Расшифровать
файл
Ввести
ключевую
фразу
Рисунок 3. Диаграмма прецедентов
3.3 Диаграмма активности
Для более детального отображения общей деятельности программы была
разработана диаграмма активности, отражающая работу приложения более
полно, учитывая действия скрытые от пользователя. Диаграмма представлена на
рисунке 4.
11
Выход
Файл
прочитан
Ожидание действий
Шифровать файл
Расшифровать файл
Выбрать файл
Выбрать файл
Файл не
выбран
Файл не
выбран
Файл выбран
Файл выбран
Получить ключевую фразу пользователя
Получитить ключевую фразу пользователя
Получить расширенные ключ
Получить расширенные ключ
Читать файл по 4 байта
Читать файл по 4 байта
Файл
прочитан
Файл не
прочитан
Файл не
прочитан
Расшифровка 4х байт
Шифрование 4х байт
Запись в файл 4х расшифрованных байт
Запись в файл 4х шифрованных байт
Рисунок 4. Диаграмма активности
3.4 Диаграмма классов
Из представленной диаграммы активности видно, что приложения удобно
реализовать в двух классах – класс, описывающий интерфейс пользователя и
класс описывающий алгоритм RC2.
12
Для спроектированных классов так же построена диаграмма из зависимости.
Диаграмма приведена на рисунке 5.
Рисунок 5. Диаграмма классов
3.5 Программная реализация
Для программной реализации алгоритма RC2, была выбрана среда Visual
Studio 2010, и язык высокоуровневого программирования C#.
В Visual Studio 2010 был создан проект приложения. Приложение, как и
задумывалось, состоит из одной формы (рис.6).
Рисунок 6. Главная форма приложения
13
Преставленную выше форму на диаграмме классов описывает класс
Form1. В нем находится вся логика для взаимодействия с пользователем, сами
же файловые операции вынесены в класс RC2, для этого в классе RC2
определене конструктор, который принимает 2 строковых переменных – путь до
файла, с которым надо работать и ключевую фразу пользователя.
Таким образом при нажатии кнопки «Шифровать»/«Расшифровать»
достаточно инициализировать объект класса шифрования введенными на форме
значениями.
В листинге ниже преставлен код, выполняющийся при нажатии кнопки
«Шифровать»:
Листинг 1. Вызов функции шифрования.
private void button2_Click( object sender, EventArgs e ) {
if ( Password == "" )
MessageBox.Show( "Ключевая фраза не должна быть
пустой", "Ошибка!", MessageBoxButtons.OK );
else if ( FileName == "" )
MessageBox.Show( "Вы не выбрали файл", "Ошибка!",
MessageBoxButtons.OK );
else {
this.rc2 = new RC2( this.FileName, this.Password );
if ( this.rc2.encrypt( ) )
MessageBox.Show( "Файл зашифрован", "Успех!",
MessageBoxButtons.OK );
}
}
Конец листинга 1.
Согласно диагамме активности и диаграмме классов, после получения
имени файла и ключевой фразы пользователя необходимо вызвать метод expand,
который
преобразует
введенную
пользователем
ключевую
фразу
в
расширенный ключ, который будет далее использоваться для выполнения
операции шифрования/расшифровавывания.
Методы expand описан в классе RC2 и является приватным, так как
непосредственно пользователю незачем его вызвывать, поэтому удобно
14
поместить вызов этого метода в конструктор класса, так как это следущий шаг
после получения пароля и имени файла.
В листинге представлен код основного конструктора класса RC2 и метод
expand.
Листинг №2. Конструктор класса RC()
ublic RC2( string _FileName, string _Password ) {
this.Password = _Password;
this.FileName = _FileName;
this.EncFileName = _FileName + ".rc2enc";
System.Text.ASCIIEncoding encoder = new ASCIIEncoding( );
byte[ ] passwordBytes = encoder.GetBytes( this.Password );
uint keyLenght = (uint)this.Password.Length;
this.xKey = this.expand(passwordBytes, keyLenght);
}
Конец листинга.
Как видно, в данном классе ключевая фраза пользователя представляется
как массив байт, используя текстовый конвертор. Дело в том что метод expand
работает с массивом байт, в качестве ключа.
В листинге ниже представлен метод expand, который на основе массива
байт и длины ключа формирует расширенный ключ.
Листинг №3. Метод expand класса RC2
private ushort[ ] expand( byte[ ] key, uint keyLenght) {
byte[ ] L = new byte[128];
ushort[ ] K = new ushort[128];
uint T = keyLenght;
uint T1 = keyLenght << 3;
uint T8 = ( T1 + 7 ) >> 3; //(T1+7)/8
uint TM = 255 % ( uint )Math.Pow( 2, 8 + T1 - 8 * T8 );
/* Размещение доставленного ключа
* в массив ключевого буффера L[0], ..., L[T-1] */
for ( int i = 0; i <= T - 1; ++i ) {
L[i] = key[i];
}
15
/* 1-й цикл операции расширения ключа */
for ( int i = ( int )T; i <= 127; ++i ) {
L[i] = piTable[( L[i - 1] + L[i - T] ) % 256];
}
/* Промежуточная операция расширения ключа */
L[128 - T8] = piTable[L[128 - T8] & TM];
/* 2-й цикл операции расширения ключа */
for ( int i = ( int )( 127 - T8 ); i >= 0; --i ) {
L[i] = piTable[L[i + 1] ^ L[i + T8]];
}
/* Последняя процедура - помещение ключевого
* буфера в выходной ключ */
for ( int i = 0; i <= 63; ++i ) {
K[i] = ( ushort )( L[2 * i] + ( L[2 * i + 1] << 8 ) );
}
return K;
}
Конец листинга.
Как видно, данный метод описан полностю по документации. Сначала
записывается имеющийся ключ в вектор L, а затем на основе трех циклов и
табилицы piTable происходит расширение ключа до 128 байт.
Далее, согласно диаграмме активности необходимо читать каждые 4 байта
файла и производить над ними операцию шифровки/расшифровки. Что бы
сделать
приложение
более
простое
для
модификации
и
понимания,
последовательность действий, котрая работает непосредственно с 4х байтовым
блоком вынесена в отдельный метод с модификатором доступа private и именем
_encrypt.
Это
сделано,
чтобы
разделить
поблочное
чтение
файла
и
преобразование блока. Сам же метод, котрый вызывает пользователь является
публичным и содержит только инструкции чтения файла поблочно и добавления
преобразованных блоков в результирующий массив байт, для записи в
зашифрованный файл.
Ниже представлен метод encrypt.
16
Листинг №4. Метод ecnrypt класса RC2.
public bool encrypt( ) {
FileStream fileStreamReader = new FileStream( this.FileName,
FileMode.Open );
FileStream fileStreamWriter = new FileStream( this.EncFileName,
FileMode.CreateNew );
BinaryWriter binaryWriter = new BinaryWriter( fileStreamWriter
);
BinaryReader binaryReader = new BinaryReader(
fileStreamReader );
List<byte> plainBytes = new List<byte>(
binaryReader.ReadBytes( (int)fileStreamReader.Length ) );
List<byte> encryptedBytes = new List<byte>( );
binaryReader.Close( );
fileStreamReader.Close( );
int countadd = plainBytes.Count % 8 ;
if ( countadd != 0 ) {
for ( int add = 0; add < 8 - countadd; add++ )
// добавляем необходимое колво байтов
plainBytes.Add( 0 );
}
for ( int blockNum = 0; blockNum < plainBytes.Count / 8;
blockNum++ ) {
byte[ ] block = plainBytes.GetRange( blockNum * 8, 8
).ToArray();
encryptedBytes.AddRange(this._encrypt(block));
}
binaryWriter.Write( encryptedBytes.ToArray( ) );
binaryWriter.Close( );
fileStreamWriter.Close( );
return true;
}
Конец листинга.
Как видно из листинга, данный метод сначала читает файл для
зашифровывания в массив байтов, затем выравнивает этот массив для
17
целочисленного количества 8ми-байтовых блоков и поблочно передает его в
функцию _encrypt, которая уже производит необходимые преобразования надо
блоком байт и возращает блок. Далее этот блок добавляется в массив
зашифрованных байт и с помощью BinaryWriter пишется в файл с расширением
.rc2encr.
Рисунок 7. Окошко успешности завершения
Далее сделаем можно посмотреть в проводник и убедиться, что
зашифрованный файл существует, причем его размер увеличился до 264 байт с
изначальных 260, так его содержимое невозможно прочитать, что говорит, о
том, что функция шифрования отработала успешно.
Ниже приведен листинг метода _ecnrypt.
Листинг №5. Метод _encrypt
private byte[ ] _encrypt( byte[ ] plaintext ) {
uint[ ] R = new uint[4];
uint[ ] S = new uint[4] { 1, 2, 3, 5 };
ushort[ ] K = this.xKey;
byte[ ] ciphertext = new byte[plaintext.Length];
/* Инициализация R[i] входным значением */
for ( int i = 0; i < 4; i++ ) {
R[i] = ( uint )( ( plaintext[2 * i + 1] << 8 ) + plaintext[2 * i]
);
}
j = 0;
// 5 mixing rounds
18
for ( int i = 0; i < 5; i++ )
mixingRound( R, S, K );
// 1 mashing round
mashingRound( R, K );
// 6 mixing rounds
for ( int i = 0; i < 6; i++ )
mixingRound( R, S, K );
// 1 mashing round
mashingRound( R, K );
// 5 mixing rounds
for ( int i = 0; i < 5; i++ )
mixingRound( R, S, K );
/* Формирование шифротекста */
for ( int i = 0; i < 4; i++ ) {
ciphertext[2 * i] = ( byte )R[i];
ciphertext[2 * i + 1] = ( byte )( R[i] >> 8 );
}
return ciphertext;
}
Конец листинга.
Данный метод так же реализован согласно официальной спецификации
алгоритма. Основывается на 18 раундах – 16 раундов смешивания и 2 раунда
объединения.
Для расшифровки шифртекста написан публичный метод decrypt и
приватный метод _decrypt. Принцип тот же, что и у методов шифрования, с той
лишь разницей, что операция выравнивания длины массива байт не нужна, так
как предпологается, что файл не поврежден и содержит шифртекст. Так же,
согласно описанию алгоритма используются раунды не mixup и mash, а r-mixup
и r-mash, т.е. обратный раундам шифрования.
Расшифрованный файл записывается с расширением .rc2decr.
19
3.6. Тестирование Windows – приложения
В разделе тестирование будет рассмотрено тестирование программы в
целях проверки реализации функциональных требований, предъявленных при
разработке программы.
Во-первых, необходимо проверить надежность программы, т.е. правильно
ли реагирует программа на то, что не был введен пароль Пример ошибки не
введенного пароля приведен на рисунке 7.
Рисунок 7. Пример ошибки при пустом пароле
На рисунке выше, представлена ошибка при отсутствии пароля,
следовательно, программа правильно реагирует на ошибку.
Так же, необходима реакция на невыбранный файл. Для этого достаточно
проверить на ненулевое значение строку с путем до файла.
Пример ошибки при невыбранном файле:
Рисунок 8. Пример ошибки при невыбранном файле
Далее необходимо проверить правильно ли шифрует и расшифровывает,
открывает и сохраняет файлы. Для этого необходимо выбрать файл для
шифрования/расшифрования, зашифровать его с введенным паролем и затем
расшифровать его с тем же паролем, для проверки результата – сравнить
входной файл и выходной расшифрованный файл.
20
Для тестирования правильности шифрования/расшифрования файла был
создан текстовый файл длиной в 260 байт. Далее этот файл подвергся
зашифровке, причем его размер возрос до 264 байт, что правильно учитывая
необходимость выравнивания длины массива байт до кратности 8, то есть до
кратности размера блока алгоритма.
Чтобы
продемонстрировать
работу
шифрования/расшифрования
на
рисунках 9,10,11 представлены файлы до шифрования, после шифрования и
после расшифрования. Стоит отметить, что на рисунке 11 видны в конце 4
нулевых байта – это как раз те байты, что были добавлены к тексты в результате
операции выравнивания длины массива байт.
Рисунок 9. Файл до шифрования.
Рисунок 10. Файл после шифрования.
Рисунок 11. Файл после расшифровки.
Для проверки правильности работы алгоритма, необходимо попробовать
зашифровать файл сторонним ПО и расшифровать разработанным приложением
и наоборот. Но, так как данный алгоритм проприетарный, то стороннего ПО,
21
реализующего его я не нашел, поэтому можно только предполагать, что
алгоритм правилен в связи с тем, что разработан по rfc2268.
22
Заключение
В
результате
работы
над
проектом
получена
работоспособное
приложение, реализующее шифрование по алгоритму RC2 в режиме работы
ECB.
При выполнении курсовой были решены следующие задачи:
- изучен стандарт алгоритма RC2 на основе rfc2268.
- изучение режима работы ECB.
- программно реализован данный алгоритм.
Решение
описанных
задач
позволило
составить
работоспособную
программную реализацию алгоритма RC2 в режиме ECB. Приложение успешно
шифрует/расшифровывает фалы, успешно обрабатывает не выровненные
файлы.
В конечном итоге были улучшены знания программирования на языке C#,
а также разобран и изучен алгоритм шифрования файлов RC2.
23
Список использованных источников
1. RFC 2268.
2. А. П. Алферов. Основы криптографии / А. Ю. Зубов, А. С. Кузьмин, А. В.
Черемушкин – Москва: Гелиос АРВ, 2005. – 480 с.
3. Брюс Шнайер, Прикладная криптография. Протоколы, алгоритмы,
исходные тексты на языке Си: Триумф: Москва, 2002.- 816 с.
24
Приложение 1
Листинг Form1.cs
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;
namespace rc2cipher {
public partial class Form1 : Form {
public string Password = "";
public string FileName = "";
private RC2 rc2;
private OpenFileDialog openFileDialog = new OpenFileDialog();
public Form1( ) {
InitializeComponent( );
}
private void Form1_Load( object sender, EventArgs e ) {
}
private void button2_Click( object sender, EventArgs e ) {
if ( Password == "" )
MessageBox.Show( "Ключевая фраза не должна быть
пустой", "Ошибка!", MessageBoxButtons.OK );
else if ( FileName == "" )
MessageBox.Show( "Вы не выбрали файл", "Ошибка!",
MessageBoxButtons.OK );
else {
this.rc2 = new RC2( this.FileName, this.Password );
if ( this.rc2.encrypt( ) )
MessageBox.Show( "Файл зашифрован", "Успех!",
MessageBoxButtons.OK );
}
}
private void button1_Click( object sender, EventArgs e ) {
if ( openFileDialog.ShowDialog( ) == DialogResult.OK ) {
this.FileName = openFileDialog.FileName;
this.label3.Text = this.FileName;
}
}
25
private void button3_Click( object sender, EventArgs e ) {
if ( Password == "" )
MessageBox.Show( "Ключевая фраза не должна быть
пустой", "Ошибка!", MessageBoxButtons.OK );
else if ( FileName == "" )
MessageBox.Show( "Вы не выбрали файл", "Ошибка!",
MessageBoxButtons.OK );
else {
this.rc2 = new RC2( this.FileName, this.Password );
if ( this.rc2.decrypt( ) )
MessageBox.Show( "Файл расшифрован", "Успех!",
MessageBoxButtons.OK );
}
}
private void textBox1_TextChanged( object sender, EventArgs e
) {
this.Password = this.textBox1.Text;
}
}
}
Листинг RC2.cs
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.IO;
namespace rc2cipher {
public class RC2 {
public string Password = "";
public string FileName = "";
private string EncFileName = "";
private string DecFileName = "";
private int j = 0;
private byte[ ] piTable =
{
0xd9,
0x28,
0xc6,
0x62,
0x17,
0x61,
0xbd,
0x78,
0xe9,
0x7e,
0x4c,
0x9a,
0x45,
0x8f,
0xf9,
0xfd,
0x37,
0x64,
0x59,
0x6d,
0x40,
0xc4,
0x79,
0x83,
0x88,
0xf5,
0x8d,
0xeb,
0x19,
0x4a,
0x2b,
0x44,
0x87,
0x09,
0x86,
0xdd,
0xa0,
0x76,
0x8b,
0xb3,
0x81,
0xb7,
0xb5,
0xd8,
0x53,
0xfb,
0x4f,
0x7d,
0x7b,
0xed,
0x9d,
0x8e,
0xa2,
0x13,
0x32,
0x0b,
26
0xf0,
0x54,
0x73,
0x12,
0x42,
0x6f,
0x27,
0xf8,
0x06,
0x08,
0x84,
0x96,
0x4b,
0xc2,
0x24,
0x99,
0xfc,
0x2d,
0x05,
0xd3,
0x63,
0x0d,
0xbb,
0xc5,
0x0a,
0x95,
0xd6,
0x56,
0x75,
0x3d,
0xbf,
0xf2,
0x11,
0xc3,
0xe8,
0xaa,
0x1a,
0x9f,
0xe0,
0x91,
0x7c,
0x02,
0x5d,
0xdf,
0x00,
0x16,
0x38,
0x48,
0xf3,
0xa6,
0x21,
0x65,
0xc0,
0xca,
0xd4,
0x0e,
0x1d,
0xc7,
0xd5,
0xea,
0x72,
0xd2,
0xd0,
0x41,
0xaf,
0x3a,
0x36,
0xfa,
0x29,
0xe6,
0x01,
0x34,
0x0c,
0xdb,
0x20,
0x22,
0x93,
0x14,
0x1f,
0x30,
0xda,
0x9b,
0xf6,
0x2f,
0xde,
0xac,
0x71,
0x5e,
0x6e,
0x50,
0x85,
0x5b,
0x98,
0x10,
0xcf,
0x3f,
0x1b,
0x5f,
0x47,
0x68,
0x5c,
0xce,
0xa7,
0x3b,
0xa3,
0x46,
0xbc,
0x90,
0xc8,
0x80,
0x35,
0x5a,
0x04,
0x0f,
0xa1,
0x23,
0x25,
0xe3,
0x67,
0xe1,
0x58,
0xab,
0xb9,
0xe5,
0xfe,
0x6b,
0x60,
0x8c,
0xbe,
0x3c,
0x69,
0x94,
0xef,
0x66,
0x52,
0x4d,
0x15,
0x18,
0x51,
0xf4,
0xb8,
0x55,
0x8a,
0x6c,
0x9e,
0xe2,
0x33,
0xb1,
0xa5,
0x7f,
0x4e,
0xb2,
0xf1,
0xe4,
0xb6,
0x07,
0x43,
0x3e,
0x1e,
0xee,
0x6a,
0x49,
0xa4,
0xcb,
0x70,
0xb4,
0x97,
0x92,
0xba,
0xa8,
0x89,
0xff,
0xcd,
0x9c,
0xc1,
0x82,
0x1c,
0xdc,
0xd1,
0x26,
0x57,
0x03,
0xe7,
0xd7,
0xf7,
0x2a,
0x74,
0xec,
0xcc,
0x39,
0x7a,
0x31,
0xae,
0xc9,
0x2c,
0xa9,
0xb0,
0x2e,
0x77,
0xad
};
private ushort[ ] xKey = new ushort[128];
public RC2( string _FileName, string _Password ) {
this.Password = _Password;
this.FileName = _FileName;
this.EncFileName = _FileName + ".rc2encr";
this.DecFileName = _FileName + ".rc2decr";
System.Text.ASCIIEncoding encoder = new ASCIIEncoding( );
byte[ ] passwordBytes = encoder.GetBytes( this.Password
);
uint keyLenght = (uint)this.Password.Length;
this.xKey = this.expand(passwordBytes, keyLenght);
}
private ushort[ ] expand( byte[ ] key, uint keyLenght) {
byte[ ] L = new byte[128];
ushort[ ] K = new ushort[128];
uint T = keyLenght;
uint T1 = keyLenght << 3;
uint T8 = ( T1 + 7 ) >> 3; //(T1+7)/8
uint TM = 255 % ( uint )Math.Pow( 2, 8 + T1 - 8 * T8 );
27
/* Размещение доставленного ключа
* в массив ключевого буффера L[0], ..., L[T-1] */
for ( int i = 0; i <= T - 1; i++ ) {
L[i] = key[i];
}
/* 1-й цикл операции расширения ключа */
for ( int i = ( int )T; i <= 127; i++ ) {
L[i] = piTable[( L[i - 1] + L[i - T] ) % 256];
}
/* Промежуточная операция расширения ключа */
L[128 - T8] = piTable[L[128 - T8] & TM];
/* 2-й цикл операции расширения ключа */
for ( int i = ( int )( 127 - T8 ); i >= 0; i-- ) {
L[i] = piTable[L[i + 1] ^ L[i + T8]];
}
/* Последняя процедура - помещение ключевого
* буфера в выходной ключ */
for ( int i = 0; i <= 63; i++ ) {
K[i] = ( ushort )( L[2 * i] + ( L[2 * i + 1] << 8 )
);
}
return K;
}
public bool encrypt( ) {
FileStream fileStreamReader
this.FileName, FileMode.Open );
FileStream fileStreamWriter
this.EncFileName, FileMode.CreateNew );
BinaryWriter binaryWriter =
fileStreamWriter );
BinaryReader binaryReader =
fileStreamReader );
= new FileStream(
= new FileStream(
new BinaryWriter(
new BinaryReader(
List<byte> plainBytes = new List<byte>(
binaryReader.ReadBytes( (int)fileStreamReader.Length ) );
List<byte> encryptedBytes = new List<byte>( );
binaryReader.Close( );
fileStreamReader.Close( );
int countadd = plainBytes.Count % 8 ;
if ( countadd != 0 ) {
for ( int add = 0; add < 8 - countadd; add++ )
28
// добавляем необходимое колво байтов
plainBytes.Add( 0 );
}
for ( int blockNum = 0; blockNum < plainBytes.Count / 8;
blockNum++ ) {
byte[ ] block = plainBytes.GetRange( blockNum * 8, 8
).ToArray();
encryptedBytes.AddRange(this._encrypt(block));
}
binaryWriter.Write( encryptedBytes.ToArray( ) );
binaryWriter.Close( );
fileStreamWriter.Close( );
return true;
}
private byte[ ] _encrypt( byte[ ] plaintext ) {
uint[ ] R = new uint[4];
uint[ ] S = new uint[4] { 1, 2, 3, 5 };
ushort[ ] K = this.xKey;
byte[ ] ciphertext = new byte[plaintext.Length];
/* Инициализация R[i] входным значением */
for ( int i = 0; i < 4; i++ ) {
R[i] = ( uint )( ( plaintext[2 * i + 1] << 8 ) +
plaintext[2 * i] );
}
j = 0;
// 5 mixing rounds
for ( int i = 0; i < 5; i++ )
mixingRound( R, S, K );
// 1 mashing round
mashingRound( R, K );
// 6 mixing rounds
for ( int i = 0; i < 6; i++ )
mixingRound( R, S, K );
// 1 mashing round
mashingRound( R, K );
// 5 mixing rounds
for ( int i = 0; i < 5; i++ )
mixingRound( R, S, K );
29
/* Формирование шифротекста */
for ( int i = 0; i < 4; i++ ) {
ciphertext[2 * i] = ( byte )R[i];
ciphertext[2 * i + 1] = ( byte )( R[i] >> 8 );
}
return ciphertext;
}
public bool decrypt( ) {
FileStream fileStreamReader
this.FileName, FileMode.Open );
FileStream fileStreamWriter
this.DecFileName, FileMode.CreateNew );
BinaryWriter binaryWriter =
fileStreamWriter );
BinaryReader binaryReader =
fileStreamReader );
= new FileStream(
= new FileStream(
new BinaryWriter(
new BinaryReader(
List<byte> plainBytes = new List<byte>(
binaryReader.ReadBytes( ( int )fileStreamReader.Length ) );
List<byte> encryptedBytes = new List<byte>( );
binaryReader.Close( );
fileStreamReader.Close( );
for ( int blockNum = 0; blockNum < plainBytes.Count / 8;
blockNum++ ) {
byte[ ] block = plainBytes.GetRange( blockNum * 8, 8
).ToArray( );
encryptedBytes.AddRange( this._decrypt( block ) );
}
binaryWriter.Write( encryptedBytes.ToArray( ) );
binaryWriter.Close( );
fileStreamWriter.Close( );
return true;
}
private byte[ ] _decrypt( byte[ ] ciphertext ) {
uint[ ] R = new uint[4];
uint[ ] S = new uint[4] { 1, 2, 3, 5 };
ushort[ ] K = xKey;
byte[ ] plaintext = new byte[ciphertext.Length];
/* Инициализация R[i] шифротекстом */
for ( int i = 0; i < 4; i++ ) {
30
R[i] = ( uint )( ( ciphertext[2 * i + 1] << 8 ) +
ciphertext[2 * i] );
}
j = 63;
// 5 r-mixing rounds
for ( int i = 0; i < 5; i++ )
rMixingRound( R, S, K );
// 1 r-mashing round
rMashingRound( R, K );
// 6 r-mixing rounds
for ( int i = 0; i < 6; i++ )
rMixingRound( R, S, K );
// 1 r-mashing round
rMashingRound( R, K );
// 5 r-mixing rounds
for ( int i = 0; i < 5; i++ )
rMixingRound( R, S, K );
/* Формирование открытого текста */
for ( int i = 0; i < 4; i++ ) {
plaintext[2 * i] = ( byte )R[i];
plaintext[2 * i + 1] = ( byte )( R[i] >> 8 );
}
return plaintext;
}
private void mixingRound( uint[ ] R, uint[ ] S, ushort[ ] K )
{
uint[ ] S1 = { 15, 14, 13, 11 };
uint[ ] S2 = { 1, 3, 7, 31 };
for ( int i = 0; i < 4; i++ ) {
// Mix up R[i]
R[i] += ( uint )( K[j] + ( uint )( ( R[rnd( i - 1 )]
& R[rnd( i - 2 )] ) + ( ( ~R[rnd( i - 1 )] ) & R[rnd( i - 3 )] ) ) );
j = j + 1;
R[i] = ( R[i] << ( int )S[i] ) + ( R[i] >> ( int
)S1[i] & S2[i] );
}
}
private void mashingRound( uint[ ] R, ushort[ ] K ) {
// Mash R[i]
for ( int i = 0; i < 4; i++ ) {
31
R[i] += K[R[rnd( i - 1 )] & 63];
}
}
private void rMixingRound( uint[ ] R, uint[ ] S, ushort[ ] K )
{
uint[ ] S1 = { 15, 14, 13, 11 };
for ( int i = 3; i >= 0; i-- ) {
// R-Mix up R[i]
R[i] &= 65535;
R[i] = ( R[i] << ( int )S1[i] ) + ( R[i] >> ( int
)S[i] );
R[i] -= ( uint )( K[j] + ( uint )( ( R[rnd( i - 1 )]
& R[rnd( i - 2 )] ) + ( ( ~R[rnd( i - 1 )] ) & R[rnd( i - 3 )] ) ) );
j = j - 1;
}
}
private void rMashingRound( uint[ ] R, ushort[ ] K ) {
// R-Mash R[i]
for ( int i = 3; i >= 0; i-- ) {
R[i] -= K[R[rnd( i - 1 )] & 63];
}
}
private int rnd( int v ) {
return ( v < 0 ) ? 4 + v : v;
}
}
}
Download