При разработке методов, реализующих шифрование и расшифрование по алгоритму 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