- •Для студентов, обучающихся по направлению
- •Введение
- •Глава 1 Средства обеспечения конфиденциальности данных
- •1.1. Классы, реализующие алгоритмы симметричного шифрования
- •1.2. Использование классов библиотеки fcl для шифрования данных
- •Имена объектов программы для элементов управления
- •Имена объектов программ для элементов управления
- •1.3. Непосредственное обращение к криптопровайдерам в приложениях для Microsoft .Net
- •Глава 2 Средства обмена секретными ключами и обеспечения аутентичности и целостности данных
- •2.1. Классы, реализующие алгоритмы асимметричного шифрования
- •2.2. Классы для вычисления и проверки эцп
- •2.3. Использование классов асимметричной криптографии
- •Имена объектов программ для элементов управления
- •Имена объектов программ для элементов управления
- •Глава 3 Средства хеширования и обеспечения целостности данных
- •3.1. Классы алгоритмов хеширования
- •3.2. Классы для вычисления и проверки кодов аутентификации сообщений
- •3.3. Использование средств хеширования и контроля целостности
- •Имена объектов программ для элементов управления
- •Контрольные вопросы
- •Библиографический список
- •Оглавление
- •Глава 1 7
- •Глава 2 40
- •Глава 3 70
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