Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
защита данных / Криптография в MS Visual Studio.doc
Скачиваний:
56
Добавлен:
31.03.2015
Размер:
743.42 Кб
Скачать

1.2. Использование классов библиотеки fcl для шифрования данных

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

На рис. 1 приведено главное окно нашего приложения.

Элементам управления окна на рис. 1 соответствуют объекты программы с именами (значениями свойства Name), указанными в табл. 1.

В примере используются и другие классы библиотеки FCL. Класс OpenFileDialog из пространства имен System. Windows. Forms предоставляет доступ к стандартному диалогу Windows открытия файла. Его основные свойства:

  • string Filter – строка фильтров (пар вида описание фильтра | фильтр), используемых для выбора отображаемых в окне диалога имен файлов;

  • bool CheckFileExists – признак проверки существования файла с введенным пользователем именем до закрытия диалогового окна;

  • bool RestoreDirectory – признак восстановления текущей папки после закрытия диалогового окна;

  • string FileName – строка с именем выбранного пользователем файла (по умолчанию пустая строка);

  • string InitialDirectory – строка, содержащая путь к папке, содержимое которой будет отображаться при создании диалогового овна.

Рис. 1. Шифрование файлов на парольной фразе

Таблица 1

Имена объектов программы для элементов управления

Элемент управления окна

Его имя в программе

Редактор для ввода (выбора) имени исходного файла

InputFName

Кнопка для выбора имени исходного файла

Browse

Выключатель для жима удаления исходного файла

DelInputFile

Редактор для отображения имени результирующего файла

OutputFName

Редактор для ввода парольной фразы

PassFrase1

Редактор для ввода подтверждения парольной фразы

PassFrase2

Элемент для выбора длины ключа

KeyLen

Кнопка «Зашифровать»

Encrypt

Кнопка «Расшифровать»

Decrypt

Кнопка «Выход»

Exit

Конструктор этого класса параметров не содержит. Основным методом класса OpenFileDialog является

DialogResult ShowDialog() – отображение диалогового окна и возвращение значения DialogResult.OK, если пользователь подтвердил выбор файла.

Класс Encoding из пространства имен System.Text используется для кодирования и декодирования текстовых строк. Его статическое свойство Unicode типа Encoding содержит строку в кодировке UTF-16, а статический метод

byte[] GetBytes(string s)

возвращает массив байт с результатом кодирования строки s.

При проверке сложности введенной пользователем парольной фразы используются следующие статические методы класса Char:

  • bool IsDigit(char c) – проверка, является ли c цифрой;

  • bool IsLower(char c) – проверка, является ли c строчной буквой;

  • bool IsUpper(char c) – проверка, является ли c прописной буквой;

  • bool IsSymbol(char c) – проверка, является ли c математическим символом.

Для вывода сообщений в программе используется класс MessageBox из пространства имен System. Windows. Forms и его статический метод

DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) – вывод сообщения с текстом text в окне с заголовком caption, кнопками buttons и пиктограммой icon).

Для получения пути к текущей папке в программе используется статический метод

string GetCurrentDirectory()

класса Directory из пространства имен System. IO.

Для удаления файла используется статический метод

void Delete(string path)

класса File из пространства имен System. IO (path – полный путь к удаляемому файлу).

Ниже приведен текст программы на языке C#:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

// подключение пространства имен криптографических классов

using System.Security.Cryptography;

// подключение пространства имен классов ввода-вывода

using System.IO;

namespace WindowsFormsApplication1

{

public partial class Form1 : Form

{

// объект класса алгоритма шифрования RC2

RC2CryptoServiceProvider rc2CSP;

// буфер для начального вектора по умолчанию

byte[] IV;

// объект класса для генерации секретного ключа из парольной фразы

PasswordDeriveBytes pdb;

// буфер для случайной примеси

byte[] randBytes;

// объекты для входного и выходного файловых потоков

FileStream finStream,foutStream;

// объект для потока шифрования-расшифрования

CryptoStream CrStream;

// буфер для ввода-вывода данных из файла

byte[] bytes;

// длина буфера ввода-вывода

int numBytesToRead;

// объект класса исключения

ArgumentException ex;

// конструктор класса формы (главного окна приложения)

public Form1()

{

InitializeComponent();

// создание объекта для криптоалгоритма

rc2CSP = new RC2CryptoServiceProvider();

// сохранение значения начального вектора по умолчанию

IV = rc2CSP.IV;

// определение режима блочного шифрования

rc2CSP.Mode = CipherMode.CFB;

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

KeySizes[] ks = rc2CSP.LegalKeySizes;

// максимально возможная для выбора длина ключа

KeyLen.Maximum = ks[0].MaxSize;

// минимально возможная длина ключа

KeyLen.Minimum = ks[0].MinSize;

// длина ключа по умолчанию

KeyLen.Value = rc2CSP.KeySize;

// шаг изменения длины ключа

KeyLen.Increment = ks[0].SkipSize;

/* запрещение прямого ввода длины ключа (возможно ее изменение только с помощью кнопок) */

KeyLen.ReadOnly = true;

}

// обработка нажатия кнопки "Выход"

private void Exit_Click(object sender, EventArgs e)

{

// закрытие главного окна

Close();

}

// обработка нажатия кнопки "Выбор файла"

private void Browse_Click(object sender, EventArgs e)

{

// создание объекта класса для диалога открытия файла

OpenFileDialog openFileDialog1 = new OpenFileDialog();

// определение свойств диалогового окна

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

openFileDialog1.Filter = "Все файлы (*.*)|*.*";

/* автоматическая проверка существования файла с введенным пользователем именем до закрытия диалога */

openFileDialog1.CheckFileExists = true;

// выбор в качестве начальной папки текущую

openFileDialog1.InitialDirectory = Directory.GetCurrentDirectory();

// восстановление текущей папки после закрытия диалога

openFileDialog1.RestoreDirectory = true;

// если пользователь выбрал файл

if (openFileDialog1.ShowDialog() == DialogResult.OK)

// сохранение и отображение имени выбранного файла

InputFName.Text = openFileDialog1.FileName;

}

// обработка нажатия кнопки "Зашифровать"

private void Encrypt_Click(object sender, EventArgs e)

{

/* признаки наличия в парольной фразе прописных и строчных букв, цифр и математических символов */

bool UpLetter=false, DownLetter=false, Digit=false, Math=false;

try

{

// проверка совпадения парольной фразы и ее подтверждения

if (PassFrase1.Text != PassFrase2.Text)

throw ex = new ArgumentException("Парольная фраза и ее подтверждение не совпадают.");

// проверка сложности введенной парольной фразы

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

{

// проверка очередного символа парольной фразы

UpLetter |= Char.IsUpper(PassFrase1.Text[i]);

DownLetter |= Char.IsLower(PassFrase1.Text[i]);

Digit |= Char.IsDigit(PassFrase1.Text[i]);

Math |= Char.IsSymbol(PassFrase1.Text[i]);

}

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

if (!UpLetter || !DownLetter || !Digit || !Math)

throw ex = new ArgumentException("Парольная фраза не соответствует условиям сложности.");

// проверка длины парольной фразы

if (PassFrase1.Text.Length < 8)

throw ex = new ArgumentException("Парольная фраза короче требуемой длины.");

// создание объекта для генерации случайной примеси

RNGCryptoServiceProvider rand =

new RNGCryptoServiceProvider();

// создание буфера для случайной примеси

randBytes = new byte[8];

// получение примеси для секретного ключа

rand.GetBytes(randBytes);

// декодирование парольной фразы

byte[] pwd = Encoding.Unicode.GetBytes(PassFrase1.Text);

// создание объекта для генерации ключа из парольной фразы

pdb = new PasswordDeriveBytes(pwd, randBytes);

// генерация ключа

rc2CSP.Key = pdb.CryptDeriveKey("RC2", "MD5",

(int)KeyLen.Value, IV);

// создание объекта шифрования

ICryptoTransform encryptor =

rc2CSP.CreateEncryptor(rc2CSP.Key, IV);

/* отображение имени зашифрованного файла (к имени исходного файла добавляется расширение .enc) */

OutputFName.Text = InputFName.Text + ".enc";

// создание объектов для файловых потоков

finStream = new FileStream(InputFName.Text, FileMode.Open);

foutStream = new FileStream(OutputFName.Text, FileMode.Create);

// запись в начало результирующего файла случайной примеси

foutStream.Write(randBytes, 0, 8);

// создание объекта для потока шифрования

CrStream = new CryptoStream(foutStream, encryptor,

CryptoStreamMode.Write);

// выделение памяти для буфера ввода-вывода

bytes = new byte[finStream.Length];

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

numBytesToRead = (int)finStream.Length;

// ввод данных из исходного файла

int n = finStream.Read(bytes, 0, numBytesToRead);

// сохранение фактического количества прочитанных байт

numBytesToRead = n;

// запись в зашифрованный файл

CrStream.Write(bytes, 0, numBytesToRead);

// очистка памяти с конфиденциальными данными

rc2CSP.Clear();

// закрытие потока шифрования

CrStream.Close();

// закрытие файлов

finStream.Close();

foutStream.Close();

// вывод сообщения о результате шифрования файла

MessageBox.Show("Файл " + InputFName.Text +

" зашифрован в файле " + OutputFName.Text +

" с эффективной длиной ключа " +

rc2CSP.EffectiveKeySize.ToString() + " бит");

/* удаление исходного файла, если выбран соответствующий режим работы */

if (DelInputFile.Checked) File.Delete(InputFName.Text);

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

InputFName.Clear();

DelInputFile.Checked = false;

OutputFName.Clear();

PassFrase1.Clear();

PassFrase2.Clear();

}

// обработка ошибки криптографической операции

catch (CryptographicException ex)

{

// вывод сообщения об ошибке

MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK,

MessageBoxIcon.Error);

// закрытие файлов

finStream.Close();

foutStream.Close();

}

// обработка остальных ошибок

catch (Exception ex)

{

// вывод сообщения об ошибке

MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK,

MessageBoxIcon.Error);

}

}

// обработка изменения текста, введенного в редактируемых строках

private void InputFName_TextChanged(object sender, EventArgs e)

{

/* есди выбрано имя исходного файла и введена парольная фраза с подтверждением, то кнопки "Зашифровать" и "Расшифровать" доступны */

Encrypt.Enabled = (InputFName.Text.Length>0) &&

(PassFrase1.Text.Length>0) && (PassFrase2.Text.Length>0);

Decrypt.Enabled = (InputFName.Text.Length > 0) &&

(PassFrase1.Text.Length > 0) && (PassFrase2.Text.Length > 0);

}

// обработка нажатия кнопки "Расшифровать"

private void Decrypt_Click(object sender, EventArgs e)

{

try

{

// проверка совпадения парольной фразы и ее подтверждения

if (PassFrase1.Text != PassFrase2.Text)

throw ex = new ArgumentException

("Парольная фраза и ее подтверждение не совпадают.");

/* создание объекта для исходного (зашифрованного) файлового потока */

finStream = new FileStream(InputFName.Text, FileMode.Open);

// создание буфера для случайной примеси

randBytes = new byte[8];

// чтение случайной примеси из начала зашифрованного файла

finStream.Read(randBytes, 0, 8);

// декодирование парольной фразы

byte[] pwd = Encoding.Unicode.GetBytes(PassFrase1.Text);

// создание объекта для генерации ключа из парольной фразы

pdb = new PasswordDeriveBytes(pwd, randBytes);

// сброс состояния объекта для алгоритма шифрования

rc2CSP.Clear();

/* генерация ключа (значение начального вектора выьирается по умолчанию) */

rc2CSP.Key = pdb.CryptDeriveKey("RC2", "MD5",

(int)KeyLen.Value, IV);

// создание объекта расшифрования

ICryptoTransform decryptor =

rc2CSP.CreateDecryptor(rc2CSP.Key, IV);

/* сохранение и отображение имени результирующего (расшифрованного) файла */

/* если расширение имени исходного файла равно .enc, то оно удаляется */

if (InputFName.Text.IndexOf(".enc") != -1)

OutputFName.Text = InputFName.Text.Substring(0,

InputFName.Text.IndexOf(".enc"));

// иначе к имени исходного файла добавляется расширение .dec

else OutputFName.Text = InputFName.Text + ".dec";

/* создание объектов для результирующего файлового потока и потока расшифрования */

foutStream = new FileStream(OutputFName.Text, FileMode.Create);

CrStream = new CryptoStream(finStream, decryptor,

CryptoStreamMode.Read);

// выделение памяти для буфера ввода-вывода

bytes = new byte[finStream.Length-8];

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

numBytesToRead = (int)(finStream.Length)-8;

// ввод данных из исходного файла

int n=CrStream.Read(bytes, 0, numBytesToRead);

// сохранение фактического количества прочитанных байт

numBytesToRead = n;

// запись в расшифрованный файл

foutStream.Write(bytes, 0, numBytesToRead);

// очистка памяти с конфиденциальными данными

rc2CSP.Clear();

// закрытие потока

CrStream.Close();

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

finStream.Close();

// закрытие результирующего файла

foutStream.Close();

// вывод сообщения о результате шифрования файла

MessageBox.Show("Файл " + InputFName.Text +

" расшифрован в файле " + OutputFName.Text);

/* удаление исходного файла, если выбран соответствующий режим работы */

if (DelInputFile.Checked) File.Delete(InputFName.Text);

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

InputFName.Clear();

DelInputFile.Checked = false;

OutputFName.Clear();

PassFrase1.Clear();

PassFrase2.Clear();

}

// обработка ошибки криптографической операции

catch (CryptographicException ex)

{

// вывод сообщения об ошибке

MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK,

MessageBoxIcon.Error);

// закрытие файлов

finStream.Close();

foutStream.Close();

}

// обработка остальных ошибок

catch (Exception ex)

{

// вывод сообщения об ошибке

MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK,

MessageBoxIcon.Error);

}

}

}

}

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

Элементам управления окна на рис. 2 соответствуют объекты программы с именами (значениями свойства Name), указанными в табл. 2.

Для работы с потоком данных в оперативной памяти в программе используется класс MemoryStream из пространства имен System. IO, имеющий конструктор без параметров и конструктор с параметром типа byte[], который задает массив байт, связываемый с потоком данных в оперативной памяти. Метод

byte[] ToArray()

этого класса позволяет получить данные из потока в оперативной памяти.

Для кодирования шифротекста перед его отображением в окне используется метод класса Encoding

string GetString(byte[] bytes, int index, int count)

позволяющий получить строку символов, соответствующую данным длиной count байт из массива bytes, начиная с элемента index.

Рис. 2. Шифрование и расшифрование введенного сообщения

Таблица 2

Соседние файлы в папке защита данных