При разработке методов, реализующих шифрование и расшифрование по алгоритму RC4 с помощью криптопровайдеров Microsoft Windows, потребуется использовать функции, экспортируемее этими криптографическими модулями и атрибут DllImport, позволяющий вызывать в программном коде, управляемом средой Framework, функции, которые будут выполняться в неуправляемом коде.
Например, в программе на языке C# в этом случае потребуется выполнить следующее:
· определить метод, создаваемый с помощью экспортируемой из криптопровайдера функции с ключевыми словами static и extern;
· добавить к определению метода атрибут DllImport, позволяющий определить имя динамически компонуемой библиотеки (DLL) криптопровайдера;
· при необходимости определить дополнительную информацию о параметрах и возвращаемом значении экспортируемой функции.
Приведем пример определения метода на основе функции CryptEncrypt (шифрование данных), экспортируемой из DLL криптопровайдера:
[DllImport ("advapi32.dll", CharSet =CharSet. Auto, SetLastError = true)]
[return: MarshalAs (UnmanagedType. Bool)]
public static extern bool CryptEncrypt (IntPtr hKey,
IntPtr hHash, int Final, uint dwFlags, byte [] pbData,
ref uint pdwDataLen, uint dwBufLen);
Здесь advapi32.dll – имя системной библиотеки, являющейся посредником между прикладной программой и криптопровайдером.
Класс DllImportAttribute (определение прототипа функции, импортируемой из внешней по отношению к среде библиотеки) определен в пространстве имен System. Runtime. InteropServices.
Поясним используемые в этом примере параметры функции CryptEncrypt:
· hKey – дескриптор (системный указатель) на секретный ключ;
· hHash – может не использоваться и задаваться нулем;
· Final – признак последней порции шифруемых данных;
· dwFlags – флаги (могут не использоваться и задаваться нулем);
· pbData – буфер с шифруемыми данными;
· pdwDataLen – длина порции шифруемых данных (после выполнения функции в этот параметр записывается фактическое число зашифрованных байт);
· dwBufLen – длина буфера с шифруемыми данными.
Для получения дескриптора секретного ключа шифрования могут использоваться функции CryptoAPI CryptDeriveKey (получение ключа из хеш-значения парольной фразы) или CryptGenKey (генерация случайного ключа).
Для расшифрования данных, зашифрованных прямым обращением к криптопровайдеру, предназначена функция CryptoAPI CryptDecrypt.
Другие функции CryptoAPI подробно описаны в [10, 12] и в документации по программированию для Windows.
После установки в операционной системе криптопровайдеров, предоставляющих реализации криптоалгоритмов, соответствующих российским стандартам, разработка новых классов-«оберток» над таким криптопровайдером производится аналогично созданию классов для представления алгоритмов, реализуемых входящими в состав Microsoft Windows криптопровайдерами.
Изменим второй пример из раздела 1.2 и будем шифровать введенный пользователем текст по алгоритму RC4, реализация которого будет импортироваться из криптопровайдера по умолчанию операционной системы Windows.
Главное окно программы приведено на рис. 3. В программе используются следующие константы, значения которых можно узнать из системного заголовочного файла wincrypt. h:
· 1 (PROV_RSA_FULL, значение провайдера по умолчанию, реализующего криптографические алгоритмы обмена ключами и электронной цифровой подписи на основе асимметричной криптосистемы RSA; используется при вызове функции CryptAcquireContext);
· 8 (CRYPT_NEWKEYSET, создание нового контейнера для ключей; более подробно о ключевых контейнерах см. в разделе 2.1);
· 0x6801 (CALG_RC4, значение кода алгоритма потокового шифрования RC4; используется при вызове функции CryptGenKey);
· 22 (PP_ENUMALGS_EX, значение параметра для получения характеристик одного из реализованных криптопровайдером алгоритмов);
· 1 (CRYPT_FIRST, значение флага для получения характеристик первого из реализованных криптоалгоритмов);
· 2 (CRYPT_NEXT, значение флага для получения характеристик второго и последующих реализованных криптоалгоритмов);
· 35 (PP_KEYX_KEYSIZE_INC, значение параметра для получения шага изменения возможной длины ключа).
Длина секретного ключа при вызове функции CryptGenKey задается старшими 16 битами параметра dwFlags [12].
Имена объектов программы, соответствующих элементам управления главного окна, используются в соответствии с табл. 2.
Ниже приведен текст программы.
using System;
using System. Collections. Generic;
using ponentModel;
using System. Data;
using System. Drawing;
using System. Linq;
using System. Text;
using System. Windows. Forms;
// подключение пространства имен классов криптографии
using System. Security. Cryptography;
// подключение классов для работы с внешними библиотеками
using System. Runtime. InteropServices;

Рис. 3. Главное окно программы
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
// дескриптор криптопровайдера
IntPtr hProv;
// дескриптор случайного секретного ключа
IntPtr key;
// длина ключа
int KeyLength;
// буфер для массива байт шифруемой строки
byte[] toEncrypt;
// длина шифрумых и зашифрованных данных
uint PlainLen, CipherLen;
// буфер для массива расшифрованных байт
byte[] encrypted;
/* определение функций, импортируемых из внешней библиотеки с реализацией криптопровайдера */
// инициализация криптопровайдера
[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);
/* структура PROV_ENUMALGS_EX для приема параметорв криптопровайдера */
[StructLayout(LayoutKind. Sequential)]
public struct PROV_ENUMALGS_EX
{
public int aiAlgid;
public int dwDefaultLen;
public int dwMinLen;
public int dwMaxLen;
public int dwProtocols;
public int dwNameLen;
[MarshalAs(ValTStr, SizeConst = 20)]
public string szName;
public int dwLongNameLen;
[MarshalAs(ValTStr, SizeConst = 40)]
public string szLongName;
}
// получение параметров криптопровайдера
[DllImport("advapi32.dll", CharSet = CharSet. Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType. Bool)]
public static extern bool CryptGetProvParam(IntPtr hProv, uint dwParam,
ref PROV_ENUMALGS_EX pbData, ref int pdwDataLen,
uint dwFlags);
// генерация случайного секретного ключа
[DllImport("advapi32.dll", CharSet = CharSet. Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType. Bool)]
public static extern bool CryptGenKey(IntPtr hProv, uint Algid,
uint dwFlags, ref IntPtr hKey);
// шифрование данных
[DllImport("advapi32.dll", CharSet = CharSet. Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType. Bool)]
public static extern bool CryptEncrypt(IntPtr hKey,
IntPtr hHash, int Final, uint dwFlags, byte[] pbData,
ref uint pdwDataLen, uint dwBufLen);
// расшифрование данных
[DllImport("advapi32.dll", CharSet = CharSet. Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType. Bool)]
public static extern bool CryptDecrypt(IntPtr hKey,
IntPtr hHash, int Final, uint dwFlags, byte[] pbData,
ref uint pdwDataLen);
// освобождение криптопровайдера
[DllImport("advapi32.dll", CharSet = CharSet. Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType. Bool)]
public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
/* результат выполнения функций, импортируемых из внешней библиотеки */
bool res;
// массив возможных значений длины ключа
int[] ks;
// конструктор класса формы главного окна программы
public Form1()
{
InitializeComponent();
// инициализация криптопровайдера
if (!CryptAcquireContext(ref hProv, null, null, 1, 0))
/* если первая попытка неудачна, инициализируем криптопровайдер с созданием контейнера ключей */
if (!CryptAcquireContext(ref hProv, null, null, 1, 8))
throw new CryptographicException
("Ошибка при инициализации криптопровайдера.");
// получение параметров длины ключа для алгоритма RC4
// создание объекта для приема значений параметров
PROV_ENUMALGS_EX data = new PROV_ENUMALGS_EX();
// задание длины буфера для приема параметров
int dlen = 100;
/* получение параметров для первого криптоалгоритма, реализованного в криптопровайдере */
if (!CryptGetProvParam(hProv, 22, ref data, ref dlen, 1))
throw new CryptographicException
("Ошибка при получении параметров длины ключа.");
// цикл до получения параметров криптовлгоритма RC4
while (data. szName!= "RC4")
CryptGetProvParam(hProv, 22, ref data, ref dlen, 2);
// получение минимально возможной длины ключа
KeyLength = data. dwMinLen;
// создание массива данных для списка
ks = new int[12];
// индексы элемента списка и выделенного элемента
int i=0, isel=0;
// максимальная длина ключа и длина ключа по умолчанию
int ksmax=data. dwMaxLen, ksdef=data. dwDefaultLen;
// получение шага изменения возможной длины ключа
// задание длины буфера дли приема данных
dlen = 4;
/* первое поле объекта data в этом случае содержит шаг изменения длины ключа */
if (!CryptGetProvParam(hProv, 35, ref data, ref dlen, 0))
throw new CryptographicException
("Ошибка при получении шага изменения длины ключа.");
// заполнение списка возможных значений длины ключа
do
{
ks[i] = KeyLength;
// сохранение индекса для длины ключа по умолчанию
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |


