|
При выполнении в лабораторной работе упражнения №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;
}
}
}-
Запустите приложение и испытайте его работу - результат может быть таким
Приложение при каждом новом создании объекта шифрования создает для него новый ключ и вектор инициализации. Если шифрованную информацию сохранять в файле, то одновременно нужно где-то запомнить имя алгоритма и его характеристики (можно только имя и секретный ключ). Это необходимо для последующей настройки объекта симметричного алгоритма шифрования на корректное восстановление информации.
-
Разберитесь с кодом примера




