Методы криптографической защиты информации Windows

Текст процедуры, выводящей в Memo-поле FileMemo формы информацию об установленных в системе криптопровайдерах, приведен ниже. Предполагается, что процедура вызывается при выборе соответствующего элемента в главном меню формы. Для краткости в тексте программы опущены фрагменты, выполняющие обработку ошибок.

type

 algInfo = record

  algID: ALG_ID;

  dwBits: DWORD;

  dwNameLen: DWORD;

  szName: array[0..100] of char;

 end;

 {вспомогательная функция, преобразующая тип провайдера в строку}

function ProvTypeToStr(provType: DWORD): string;

begin

 case provType of

  PROV_RSA_FULL: ProvTypeToStr := 'RSA full provider';

  PROV_RSA_SIG: ProvTypeToStr := 'RSA signature provider';

  PROV_DSS: ProvTypeToStr := 'DSS provider';

  PROV_DSS_DH: ProvTypeToStr := 'DSS and Diffie-Hellman provider';

  PROV_FORTEZZA: ProvTypeToStr := 'Fortezza provider';

  PROV_MS_EXCHANGE: ProvTypeToStr := 'MS Exchange provider';

  PROV_RSA_SCHANNEL: ProvTypeToStr := 'RSA secure channel provider';

  PROV_SSL: ProvTypeToStr := 'SSL provider';

 else

  ProvTypeToStr := 'Unknown provider';

 end;

end;

{вспомогательная функция, преобразующая тип реализации в строку}

function ImpTypeToStr(it: DWORD): string;

begin

 case it of

  CRYPT_IMPL_HARDWARE: ImpTypeToStr := 'аппаратный';

  CRYPT_IMPL_SOFTWARE: ImpTypeToStr := 'программный';

  CRYPT_IMPL_MIXED: ImpTypeToStr := 'смешанный';

  CRYPT_IMPL_UNKNOWN: ImpTypeToStr := 'неизвестен';

 else

  ImpTypeToStr := 'неверное значение';

 end;

end;

{процедура вывода информации о криптопровайдерах}

procedure TMainForm.InfoItemClick(Sender: TObject);

var

 i: DWORD;

 dwProvType, cbName, DataLen: DWORD;

 provName: array[0..200] of char;

 vers: array[0..3] of byte;

 impType: DWORD;

 ai: algInfo;

 err: string;

begin

 i := 0;

 FileMemo.Clear;

 while (CryptEnumProviders(i, nil, 0, {проверяем наличие еще одного}

  @dwProvType, nil, @cbName)) do

 begin

  if CryptEnumProviders(i, nil, 0, {получаем имя CSP}

  @dwProvType, @provName, @cbName) then

  begin

  FileMemo.Lines.Add('Криптопровайдер: ' + provName);

  FileMemo.Lines.Add('Тип: ' + IntToStr(dwProvType) + ' - ' +

  ProvTypeToStr(dwProvType));

  if not CryptAcquireContext(@hProv, nil, provName, dwProvType,

  CRYPT_VERIFYCONTEXT) then

  begin

  {обработка ошибок}

  end;

  DataLen := 4;

  if not CryptGetProvParam(hProv, PP_VERSION, (@vers), @DataLen, 0) then

  begin

  {обработка ошибок}

  end;

  FileMemo.Lines.Add('Версия: ' + chr(vers[1] + ) + '.' + chr(vers[0] + ));

  if not CryptGetProvParam(hProv, PP_IMPTYPE, @impType, @DataLen, 0) then

  begin

  {обработка ошибок}

  end;

  FileMemo.Lines.Add('Тип реализации: ' + ImpTypeToStr(impType));

  FileMemo.Lines.Add('Поддерживает алгоритмы:');

  DataLen := sizeof(ai);

  if not CryptGetProvParam(hProv, PP_ENUMALGS, @ai, @DataLen, CRYPT_FIRST)

  then

  begin

  {обработка ошибок}

  end;

  with ai do

  FileMemo.Lines.Add(szName + #9 + 'длина ключа - ' + IntToStr(dwBits) +

  ' бит' + #9 + 'ID: ' + IntToStr(AlgID));

  DataLen := sizeof(ai);

  while CryptGetProvParam(hProv, PP_ENUMALGS, @ai, @DataLen, 0) do

  begin

  with ai do

  FileMemo.Lines.Add(szName + #9 + 'длина ключа - '

  + IntToStr(dwBits) + ' бит' + #9 + 'ID: ' + IntToStr(AlgID));

  DataLen := sizeof(ai);

  end;

  FileMemo.Lines.Add('');

  CryptReleaseContext(hProv, 0);

  end;

  inc(i);

 end;

end;

На рис. 2 показан пример отчета, выдаваемого приведенным выше кодом, выполненным в среде Windows 98.
Шифрование с использованием паролей
После того как мы узнали кое-что о структуре CryptoAPI, можно воспользоваться ею в практических целях. Пожалуй, самым ожидаемым действием криптографической подсистемы является шифрование файлов — так, чтобы лишь пользователь, знающий определенный пароль, мог получить к ним доступ.
Для шифрования данных в CryptoAPI применяются симметричные алгоритмы. Симметричность означает, что для шифрования и расшифровки данных используется один и тот же ключ, известный как шифрующей, так и расшифровывающей стороне. При этом плохо выбранный ключ шифрования может дать противнику возможность взломать шифр. Поэтому одной из функций криптографической подсистемы должна быть генерация «хороших» ключей либо случайным образом, либо на основании некоторой информации, предоставляемой пользователем, например пароля.
В случае создания ключа на основании пароля должно выполняться следующее обязательное условие: при многократном повторении процедуры генерации ключа на одном и том же пароле должны получаться идентичные ключи. Ключ шифрования имеет, как правило, строго определенную длину, определяемую используемым алгоритмом, а длина пароля может быть произвольной. Даже интуитивно понятно, что для однозначной генерации ключей нужно привести разнообразные пароли к некоторой единой форме. Это достигается с помощью хеширования.
Хешированием (от англ. hash — разрезать, крошить, перемешивать) называется преобразование строки произвольной длины в битовую последовательность фиксированной длины (хеш-значение, или просто хеш) с обеспечением следующих условий:
по хеш-значению невозможно восстановить исходное сообщение;
практически невозможно найти еще один текст, дающий такой же хеш, как и наперед заданное сообщение;
практически невозможно найти два различных текста, дающих одинаковые хеш-значения (такие ситуации называют коллизиями).
При соблюдении приведенных условий хеш-значение служит компактным цифровым отпечатком (дайджестом) сообщения. Существует множество алгоритмов хеширования. CryptoAPI поддерживает, например, алгоритмы MD5 (MD — Message Digest) и SHA (Secure Hash Algorithm).
Итак, чтобы создать ключ шифрования на основании пароля, нам нужно вначале получить хеш этого пароля. Для этого следует создать с помощью CryptoAPI хеш-объект, воспользовавшись функцией CryptCreateHash (провайдер, ID_алгоритма, ключ, флаги, хеш), которой нужно передать дескриптор криптопровайдера (полученный с помощью CryptAcquireContext) и идентификатор алгоритма хеширования (остальные параметры могут быть нулями). В результате мы получим дескриптор хеш-объекта. Этот объект можно представить себе как черный ящик, который принимает любые данные и «перемалывает» их, сохраняя внутри себя лишь хеш-значение. Подать данные на вход хеш-объекта позволяет функция CryptHashData (дескриптор, данные, размер_данных, флаги).

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...