При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.Xna.Framework.Graphics;
namespace Application1 { public partial class MainForm : Form { // Объявим поле графического устройства для видимости в методах GraphicsDevice device;
public MainForm() { InitializeComponent();
// Подпишемся на событие Load формы this.Load += new EventHandler(MainForm_Load);
// Попишемся на событие FormClosed формы this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed); }
void MainForm_FormClosed(object sender, FormClosedEventArgs e) { // Удаляем (освобождаем) устройство device.Dispose(); // На всякий случай присваиваем ссылке на устройство значение null device = null; }
void MainForm_Load(object sender, EventArgs e) { // Создаем объект представления для настройки графического устройства PresentationParameters presentParams = new PresentationParameters(); // Настраиваем объект представления через его свойства presentParams.IsFullScreen = false; // Включаем оконный режим presentParams.BackBufferCount = 1; // Включаем задний буфер // для двойной буферизации // Переключение переднего и заднего буферов // должно осуществляться с максимальной эффективностью presentParams.SwapEffect = SwapEffect.Discard; // Устанавливаем размеры заднего буфера по клиентской области окна формы presentParams.BackBufferWidth = this.ClientSize.Width; presentParams.BackBufferHeight = this.ClientSize.Height;
// Создадим графическое устройство с заданными настройками device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware, this.Handle, presentParams); }
protected override void OnPaint(PaintEventArgs e) { device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.OnPaint(e); } } } Выбрасывается исключение: Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Работа с потоками данных
Упражнение 9. Защита данных с помощью потока CryptoStream
Часто встречаются ситуации, когда при хранении и передаче данных их защита является основополагающим требованием к приложению. Для защиты данных обычно применяют шифрование с секретным ключем. Одним из способов решения задачи шифрования является применение класса CryptoStream из пространства имен System.Security.Cryptography библиотеки mscorlib.dll. Этот класс служит оболочкой над другими потоками и выполняет криптографические операции над передаваемыми данными.
В основе шифрования .NET лежат три абстрактных класса, которые порождают экземплярные классы для реализации следующих криптографических алгоритмов:
- SymmetricAlgorithm - симметричные алгоритмы, которые для шифрования и дешифрования информации используют один и тот же ключ. Производными от класса SymmetricAlgorithm являются тоже абстрактные классы:
-
AsymmetricAlgorithm - асимметричные алгоритмы, которые для шифрования и дешифрования применяют разные ключи. Асимметричные криптографические алгоритмы также называют инфраструктурой открытого ключа ( PKI - Public Key Infrastructure )
Производными от класса AsymmetricAlgorithm являются тоже абстрактные классы:
- DSA
- ECDiffieHellman
- ECDsa
- RSA
-
HashAlgorithm - алгоритмы хеширования или дайджеста сообщения, преобразующие первоначальный текст любой длины в шифрованный текст фиксированной длины. Они выполняют односторонне шифрование, а это значит, что из полученного хешированием шифротекста нельзя восстановить первоначальный документ. Фиксированная длина хеша зависит от применяемого алгоритма и находится в пределах от 16 до 32 байтов.
Производными от класса HashAlgorithm являются тоже абстрактные классы:
- KeyedHashAlgorithm
- MD5
- RIPEMD160
- SHA1
- SHA256
- SHA384
- SHA512
Поскольку перечисленные классы являются абстрактными, то для создания экземплярных объектов они используют классы провайдеров ( Provider - поставщик) или менеджеров ( Manager - управленец).
Криптография - это целая ветвь математики, создающая модели и алгоритмы для шифрования и дешифрования сообщений. Не вдаваясь в подробности криптографии мы просто проиллюстрируем работу потока CryptoStream на нескольких примерах.
Введение в симметричные алгоритмы .NET
Да простят меня классики за непоследовательность изложения и хотя наша тема потоки, все же вначале посмотрим краешком на классы симметричных алгоритмов, чтобы лучше понять коды приводимых ниже примеров.
Симметричные алгоритмы обычно намного быстрее асимметричных и они хорошо выполняют операции шифрования-дешифрования объемных файлов. Пространство имен System.Security.Cryptography поддерживает симметричные алгоритмы DES, RC2, Rijndael и TripleDES. Только у алгоритма Rijndael есть своя управляемая реализация, остальные поставляются из Microsoft Crypto API готовыми с помощью провайдеров.
Все классы симметричных алгоритмов наследуют от своего общего предка SymmetricAlgorithm, который предоставляет им ряд общих методов и свойств, некоторые из которых приведены в таблице
Рассмотрим работу семметричных алгоритмов на примерах.
Пример 1. Поток CryptoStream и шифрование в память
- Создайте новое решение CryptoStream с проектом Demo1 так
- Настройте форму в соответствии со следующей таблице свойств
- Выделите все элементы формы командой Edit/Select All и замкните созданный интерфейс командой Format/Lock Controls
-
Выделите все текстовые блоки, кроме txtSourceData, и задайте для них
- BorderStyle=FixedSingle
-
Выделите все элементы, кроме TextBox и GroupBox, и задайте для них
- AutoSize=True
Созданный интерфейс должен получиться таким
- Выделите все текстовые блоки, кроме txtSourceData, и создайте для них общие обработчики событий KeyDown и KeyPress для блокировки редактирования (имена обработчиков введите вручную)
- Командой Project/Add Class добавьте новый класс с именем ExecuteCryptography.cs и заполните его следующим кодом (приводится полностью)
using System; using System.IO; using System.Text; using System.Security.Cryptography; namespace Demo1 { class ExecuteCryptography { // Создаем кодировщик символов private UTF7Encoding utf7 = new UTF7Encoding(); // Объявляем ссылки на шифровальщик, // на массивы Key и IV (Initialization Vector) private SymmetricAlgorithm codec; private byte[] key; private byte[] initVector;// IV // Конструктор public ExecuteCryptography(SymmetricAlgorithm codec) { this.key = codec.Key; this.initVector = codec.IV; this.codec = codec; } public string Encrypt(string text) { byte[] input = utf7.GetBytes(text); byte[] output = Transform(input, codec.CreateEncryptor(key, initVector)); return Convert.ToBase64String(output); } public string Decrypt(string text) { byte[] input = Convert.FromBase64String(text); byte[] output = Transform(input, codec.CreateDecryptor(key, initVector)); return utf7.GetString(output); } private byte[] Transform(byte[] input, ICryptoTransform cryptoTransform) { // Создаем потоки MemoryStream memoryStream = // Поток памяти new MemoryStream(); CryptoStream cryptoStream = // Шифропоток-оболочка new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write); // Кодируем в поток памяти через шифропоток cryptoStream.Write(input, 0, input.Length); cryptoStream.FlushFinalBlock(); // Преобразуем заполненный поток памяти в массив байтов byte[] result = memoryStream.ToArray(); // Останавливаем потоки memoryStream.Close(); cryptoStream.Close(); // Возвращаем кодированное/раскодированное return result; } // Перегруженные методы public byte[] Encrypt(byte[] input) { return Transform(input, codec.CreateEncryptor(key, initVector)); } public byte[] Decrypt(byte[] input) { return Transform(input, codec.CreateDecryptor(key, initVector)); } } }
В приведенном коде поток памяти мы заключили в оболочку потока шифрования. Но можно пойти еще дальше и для удобства поток шифрования, в свою очередь, заключить в оболочку текстового потока StreamWriter, например так
MemoryStream memoryStream = // Поток памяти new MemoryStream(); CryptoStream cryptoStream = // Шифропоток-оболочка new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write); StreamWriter streamWriter = new StreamWriter(cryptoStream); streamWriter.Write(txtSourceData.Text); streamWriter.Flush(); cryptoStream.FlushFinalBlock();
- Заполните файл Form1.cs следующим кодом (приводится полностью)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; // Дополнительные пространства имен using System.Security.Cryptography; using System.IO; namespace Demo1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Подписываемся на событие Click кнопки btnExecute.Click += btnExecute_Click; } // Обработчик кнопки private void btnExecute_Click(object sender, EventArgs e) { // Создаем объект симметричного шифрования SymmetricAlgorithm codec = null;// Тип общего предка switch (SelectedRadio().Trim()) { case "DES": codec = new DESCryptoServiceProvider(); break; case "RC2": codec = new RC2CryptoServiceProvider(); break; case "Rijndael": codec = new RijndaelManaged(); break; case "TripleDES": codec = new TripleDESCryptoServiceProvider(); break; case "SymmetricAlgorithm": codec = SymmetricAlgorithm.Create(); break; default: MessageBox.Show("Выделите провайдер шифрования"); return; } // Создаем экземпляр нашего класса // и передаем ему выбранный шифровальшик ExecuteCryptography executeCryptography = new ExecuteCryptography(codec); // Шифруем текст string sourceData = txtSourceData.Text; string encryptedData = executeCryptography.Encrypt(sourceData); txtEncryptedData.Text = encryptedData; // Расшифровываем текст string decryptedData = executeCryptography.Decrypt(encryptedData); txtDecryptedData.Text = decryptedData; ////////////////////////////////////////////////// // Показываем характеристики алгоритма шифрования ////////////////////////////////////////////////// { txtKey.Text = Encoding.UTF7.GetString(codec.Key);// Key txtIV.Text = Encoding.UTF7.GetString(codec.IV);// Initialization Vector txtKeySize.Text = codec.KeySize.ToString();// KeySize StringBuilder sb = new StringBuilder(); foreach (KeySizes sizes in codec.LegalKeySizes) { sb.Append(sizes.MinSize.ToString() + "-" + sizes.MaxSize.ToString() + " (" + sizes.SkipSize.ToString() + ") "); } txtLegalKeySizes.Text = sb.ToString();// LegalKeySizes txtBlockSize.Text = codec.BlockSize.ToString();// BlockSize sb = new StringBuilder(); foreach (KeySizes sizes in codec.LegalBlockSizes) { sb.Append(sizes.MinSize.ToString() + "-" + sizes.MaxSize.ToString() + " (" + sizes.SkipSize.ToString() + ") "); } txtLegalBlockSizes.Text = sb.ToString();// LegalBlockSizes } } // Динамически ищем включенный RadioButton string SelectedRadio() { string tag = ""; foreach (Control ctrl in groupBox1.Controls) { RadioButton radio = ctrl as RadioButton;// Приводим ссылку if (radio.Checked) { tag = (String)radio.Tag;// Приводим ссылку break; } } return tag; } // Блокировка редактирования всех целевых TextBox private void txtTarget_KeyDown(object sender, KeyEventArgs e) { e.Handled = true; } private void txtTarget_KeyPress(object sender, KeyPressEventArgs e) { e.Handled = true; } } }
- Запустите приложение и испытайте его работу - результат может быть таким
Приложение при каждом новом создании объекта шифрования создает для него новый ключ и вектор инициализации. Если шифрованную информацию сохранять в файле, то одновременно нужно где-то запомнить имя алгоритма и его характеристики (можно только имя и секретный ключ). Это необходимо для последующей настройки объекта симметричного алгоритма шифрования на корректное восстановление информации.
- Разберитесь с кодом примера