- •Для студентов, обучающихся по направлению
- •Введение
- •Глава 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
3.2. Классы для вычисления и проверки кодов аутентификации сообщений
В состав библиотеки FCL входят следующие классы, предназначенные для вычисления кодов аутентификации сообщений (MAC, message authentication code) и контроля целостности информации:
на основе хеширования с секретным ключом по алгоритмам MD5, RIPEMD или SHA (абстрактный базовый класс HMAC и его наследники HMACMD5, HMACRIPEMD160, HMACSHA1, HMACSHA256, HMACSHA384 и HMACSHA512);
на основе алгоритма симметричного шифрования TripleDES (класс MACTripleDES).
Общим абстрактным базовым классом для классов контроля целостности является класс KeyedHashAlgorithm, являющийся наследником класса HashAlgorithm. В классе KeyedHashAlgorithm определено дополнительное свойство:
byte[] Key – секретный ключ, используемый при вычислении и проверке кода аутентификации сообщения.
В классе HMAC определены дополнительные свойства:
int BlockSizeValue – длина блока, используемого при вычислении хеш-значения, в байтах;
string HashName – имя алгоритма хеширования, используемого при вычислении и проверке кода аутентификации сообщения.
Классы HMACMD5, HMACRIPEMD160, HMACSHA1, HMACSHA256, HMACSHA384 и HMACSHA512 имеют конструкторы без параметров и конструкторы с параметром
byte[] key – секретный ключ, который будет использоваться объектом класса при вычислении и проверке кода аутентификации сообщений.
Класс HMACSHA1 имеет еще один дополнительный конструктор с параметрами
byte[] key, bool useManagedSha1 – создание объекта с заданным секретным ключом и использованием управляемой реализации алгоритма SHA1, если второй параметр равен true, или реализации этого алгоритма в криптопровайдере в неуправляемом коде, если значением второго параметра является false.
Класс MACTripleDES имеет конструктор без параметров, а также конструкторы с параметрами:
byte[] rgbKey – создание объекта с заданным параметром секретного ключа;
string strTripleDES, byte[] rgbKey – создание объекта с заданной реализацией алгоритма strTripleDES и заданным секретным ключом rgbKey (реализацией алгоритма TripleDES по умолчанию является System.Security.Cryptography.TripleDES).
Длина ключа, используемая объектами класса MACTripleDES, должна быть 8, 16 или 24 байта.
3.3. Использование средств хеширования и контроля целостности
Рассмотрим примеры использования в приложениях для Microsoft .Net классов, реализующих алгоритмы хеширования и вычисления кодов аутентификации сообщений. В первом примере создадим программу для вычисления хеш-значения по алгоритму RIPEMD160 для двух вводимых пользователем сообщений.
На рис. 6 приведено главное окно программы, а в табл. 5 – соответствие между элементами управления главного окна и их именами в программе.
Рис. 6. Окно программы хеширования
Таблица 5
Имена объектов программ для элементов управления
Элемент управления окна |
Его имя в программе |
Редактор для ввода текста первого сообщения |
Message1 |
Редактор для ввода текста второго сообщения |
Message2 |
Строка для отображения хеш-значения |
HashValue |
Кнопка «Выход» |
Exit |
Для отображения вычисленного хеш-значения в шестнадцатеричном формате в программе используется статический метод класса string
string Format(string format, Object arg0) – преобразование значения arg0 в строку в соответствии с форматной строкой format (для отображения значения байта в виде двух шестнадцатеричных цифр с обязательным выводом нуля используется формат "{0,2:X2}").
Чтобы проверить правильность выполненного хеширования в программе символы введенных сообщений преобразуются в кодировку ASCII с помощью одноименного статического свойства класса Encoding и его метода GetBytes, рассмотренного в разделе 1.2.
Ниже приведен текст программы:
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;
namespace WindowsFormsApplication6
{
// класс главного окна
public partial class Form1 : Form
{
// объект для алгоритма хеширования
RIPEMD160Managed ripemd;
// данные из первого сообщения
byte[] bytes1;
// данные из второго сообщения
byte[] bytes2;
// хеш-значение
byte[] hash;
// конструктор класса главного окна
public Form1()
{
InitializeComponent();
// создание объекта хеширования
ripemd = new RIPEMD160Managed();
}
// обработка нажатия кнопки "Выход"
private void Exit_Click(object sender, EventArgs e)
{
Close();
}
/* обработка изменения текста в любом их двух редакторов для ввода сообщений */
private void Message1_TextChanged(object sender, EventArgs e)
{
// очистка поля для отображения хеш-значения
HashValue.Text=»»;
// данные для хеширования
byte[] data;
// получение данных первого сообщения
bytes1=Encoding.ASCII.GetBytes(Message1.Text);
// получение данных второго сообщения
bytes2 = Encoding.ASCII.GetBytes(Message2.Text);
// выделение памяти для хешируемых данных
data=new byte[bytes1.Length+bytes2.Length];
// объединение данных двух сообщений
bytes1.CopyTo(data, 0);
bytes2.CopyTo(data, bytes1.Length);
// получение хеш-значения
hash = ripemd.ComputeHash(data);
// отображение хеш-значения в шестнадцатеричном формате
for(int i=0; i<hash.Length; i++)
HashValue.Text+=string.Format(“{0,2:X2}”, hash[i]);
}
}
}
Во втором примере этого раздела покажем, как в программе на языке C# использовать алгоритмы хеширования, реализации которых отсутствуют в библиотеке FCL. Для этого нам придется использовать функции CryptoAPI, рассмотренные в разделе 1.3, и некоторые дополнительные функции этого интерфейса, такие как CryptCreateHash, CryptHashData и CryptGetHashParam.
Изменим программу из предыдущего примера и будем вычислять хеш-значение двух сообщений по алгоритму MD4 (окно измененной программы приведено на рис. 7).
В этой программе используются еще две константы, передаваемые функциям CryptoAPI и определенные в файле wincrypt.h:
4 (HP_HASHSIZE, значение параметра для получения длины хеш-значения, генерируемого алгоритмом хеширования);
2 (HP_HASHVAL, значение параметра для получения вычисленного хеш-значения);
0x8002 (CALG_MD4, код алгоритма хеширования MD4).
Первые две константы используются при вызове функции CryptGetHashParam, а третья – CryptCreateHash.
Рис. 7. Главное окно программы хеширования
Ниже приведен текст измененной программы из предыдущего примера:
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.Runtime.InteropServices;
namespace WindowsFormsApplication6
{
// класс главного окна
public partial class Form1 : Form
{
// дескриптор криптопровайдера
IntPtr hProv;
// дескриптор объекта хеширования
IntPtr hHash;
// данные из первого сообщения
byte[] bytes1;
// данные из второго сообщения
byte[] bytes2;
// хеш-значение
byte[] hash;
/* определение функций, импортируемых из внешней библиотеки с реализацией криптопровайдера */
// инициализация криптопровайдера
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(ref IntPtr hProv,
string pszContainer, string pszProvaider,
uint dwProvType, uint dwFlags);
// инициализация объекта хеширования
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptCreateHash(IntPtr hProv, uint Algid,
IntPtr hKey, uint dwFlags, ref IntPtr hHash);
// хеширование данных
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptHashData(IntPtr hHash, byte[] pbData,
uint dwDataLen, uint dwFlags);
// получение хеш-значения
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGetHashParam(IntPtr hHash, uint dwParam,
byte[] pbData, ref uint pdwDataLen, uint dwFlags);
// разрушение объекта хеширования
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDestroyHash(IntPtr hHash);
// освобождение криптопровайдера
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
// конструктор класса главного окна
public Form1()
{
InitializeComponent();
// инициализация криптопровайдера
if (!CryptAcquireContext(ref hProv, null, null, 1, 0))
/* если первая попытка неудачна, инициализируем криптопровайдер с созданием контейнера ключей */
if (!CryptAcquireContext(ref hProv, null, null, 1, 8))
throw new CryptographicException
("Ошибка при инициализации криптопровайдера.");
}
// обработка нажатия кнопки "Выход"
private void Exit_Click(object sender, EventArgs e)
{
// освобождение криптопровайдера
CryptReleaseContext(hProv, 0);
// закрытие окна программы
Close();
}
/* обработка изменения текста в любом их двух редакторов для ввода сообщений */
private void Message1_TextChanged(object sender, EventArgs e)
{
// длина параметра объекта хеширования
uint hashlen;
// очистка поля для отображения хеш-значения
HashValue.Text="";
// данные для хеширования
byte[] data;
// получение данных первого сообщения
bytes1=Encoding.ASCII.GetBytes(Message1.Text);
// получение данных второго сообщения
bytes2 = Encoding.ASCII.GetBytes(Message2.Text);
// выделение памяти для хешируемых данных
data=new byte[bytes1.Length+bytes2.Length];
// объединение данных двух сообщений
bytes1.CopyTo(data, 0);
bytes2.CopyTo(data, bytes1.Length);
// инициализация объекта хеширования
if(!CryptCreateHash(hProv, 0x8002, (IntPtr)null, 0, ref hHash))
throw new CryptographicException
("Ошибка при инициализации объекта хеширования.");
// хеширование данных
if(!CryptHashData(hHash, data, (uint)data.Length, 0))
throw new CryptographicException
("Ошибка при хешировании данных.");
/* задание длины параметра, получаемого функцией CryptGetHashParam */
hashlen = 4;
// выделение памяти для буфера с получаемой длиной хеш-значения
hash = new byte[hashlen];
// получение длины хеш-значения
if (!CryptGetHashParam(hHash, 4, hash, ref hashlen, 0))
throw new CryptographicException
("Ошибка при получении длины хеш-значения.");
// сохранение полученной длины хеш-значения
uint hashsize = (uint)hash[0];
// выделение памяти для хеш-значения
hash = new byte[hashsize];
// получение вычисленного хеш-значения
if(!CryptGetHashParam(hHash, 2, hash, ref hashsize, 0))
throw new CryptographicException
("Ошибка при получении хеш-значения.");
// отображение хеш-значения в шестнадцатеричном формате
for(int i=0; i<hashsize; i++)
HashValue.Text+=string.Format("{0,2:X2}", hash[i]);
// разрушение объекта хеширования
CryptDestroyHash(hHash);
}
}
}