Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Подземелье Магов
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  10:59[Войти] | [Зарегистрироваться]

Работаем с криптопровайдером от Крипто-Про

SomeName SomeSurname
дата публикации 07-08-2007 03:18

Работаем с криптопровайдером от Крипто-Про

В данной статье я не буду пересказывать MSDN, а просто рассмотрю некоторые вопросы, с которыми столкнулся, работая с данным криптопровайдером. Как показывает практика, он достаточно распространен в России. Используется, в том числе, в системах передачи бухгалтерской и налоговой отчетности через интернет.

1. Шифрование.

Как известно, шифрование в CryptoApi может осуществляться низкоуровневыми функциями, а может и высокоуровневыми (message-oriented) функциями. Я буду рассматривать низкоуровневые функции, ибо для высокоуровневых есть готовые вполне пригодные примеры из MSDN.

Пусть есть пользователь А, и пользователь Б. Оба пользователя имеют по уникальной ключевой паре. Отметим, что ключевая пара может быть либо AT_KEYEXCHANGE либо AT_SIGNATURE. Обе эти ключевые пары пригодны и для шифрования, и для подписи. Но должна быть договоренность о том, какая пара используется, ибо пары AT_KEYEXCHANGE и AT_SIGNATURE разные.

Предположим, что пользователь А желает зашифровать сообщение для Б.

Он может действовать по следующей схеме: сгенерировать сессионный ключ, зашифровать сообщение этим сессионным ключом, зашифровать сессионный ключ с помощью публичного ключа пользователя Б. Для того, чтобы Б смог расшифровать сообшение от А, ему нужны: зашифрованный сессионный ключ, вектор инициализации, публичный ключ А, и собственно сами зашифрованные данные.

Принцип зашифровки сессионного ключа таков: данные ключа шифруются с помощью ключа согласования, который может быть получен одним из двух способов: либо из публичного ключа А и ключевой пары Б, либо из публичного ключа Б и ключевой пары А.

Общая схема шифрования такова.

  • Получаем хэндл своей ключевой пары
  • Импортируем открытый ключ получателя на свою ключевую пару
  • Генерируем сессионный ключ (указываем алгоритм шифрования)
  • Устанавливаем режим шифрования
  • Экспортируем сессионный ключ в зашифрованном виде
  • Извлекаем вектор инициализации
  • Шифруем сообщение.

Для успешной расшифровки получателю необходимо иметь:

  1. Публичный ключ отправителя
  2. Свою ключевую пару, на публичном ключе которой шифровался сессионный ключ
  3. Шифрованный сессионный ключ
  4. Вектор инициализации
  5. Зашифрованные данные.
  6. Режим шифрования
  7. Идентификатор алгоритма шифрования

Код, осуществляющий шифрацию и дешифрацию данных, можно посмотреть в приложении к статье (класс TCrypter). Кроме того, в приложении есть и другие криптоориентированные классы, не рассмотренные в данной статье. Например, класс Tcert - для работы с сертификатами (получение некоторых свойств, запись в поток, извлечение публичного ключа, получение хэндла ключевой пары, связанной с сертификатом).

Позволю себе подчеркнуть некоторые важные моменты, с которыми столкнулся при разработке класса TCrypter для работы с криптопровайдером КРИПТО-ПРО.

  1. Режим шифрования выставлять крайне желательно, ибо при несоответствии режимов шифрации и дешифрации при расшифровке получится не тот текст, который был зашифрован.
  2. При некоторых режимах шифрования размер памяти, выделенной под буфер, в котором передаются данные функции CryptEncrypt, должен быть кратен размеру блока (CryptGetKeyParam(…,KP_BLOCKSIZE,…)). Для простоты и расширяемости удобно всегда выделять память под означенный буфер кратно размеру блока.
  3. При каждом(!) использовании функции CryptEncrypt/CryptDecrypt меняется вектор инициализации. Это верно для Крипто-Про, для провайдеров от Микрософт такого поведения не выявлено. Поэтому при организации поблочного шифрования/дешифрования необходимо либо сохранять векторы инициализации для каждого блока, либо принудительно выставлять вектор инициализации перед шифрованием/дешифрованием каждого блока с помощью CryptSetKeyParam(..,KP_IV,..).

Список режимов шифрования можно посмотреть в файле wcrypt2.pas. Устанавливается режим так:

Var Param: Cardinal;
...
Param := CRYPT_MODE_CFB;

if not CryptSetKeyParam(hSessionKey,KP_MODE,@Param,0) then
   raise TCryptException.Create(ceOtherCryptError);

2. Цифровая подпись и проверка.

Непосредственно данные не подписываются. Подписывается значение хэш-функции, вычисленное на этих данных. При проверке подписи под документом, также вычисляется хэш.

Предположим, что мы подписываем одни и те же данные несколько раз. В результате все полученные подписи будут различными! Поэтому для проверки подписи выделена специальная функция CryptVerifySignature.

Для подписи данных нужно:
  1. создать объект хэш ( CryptCreateHash)
  2. вычислить значение хэш-функции от подписываемых данных (CryptHashData)
  3. собственно подписать хэш (CryptSignHash)
Для проверки подписи нужно:
  1. создать объект хэш ( CryptCreateHash)
  2. вычислить значение хэш-функции от подписываемых данных (CryptHashData)
  3. проверить подпись (CryptVerifySignature)

Заметим, что для провайдера КРИПТО-ПРО, судя по документации, можно выставлять набор параметров с помощью CryptSetHashParam(…,HP_OID,…), передавая туда указатель на строку с параметрами, например '1.2.643.2.2.9'.

Вот список возможных вариантов параметров:
const
   OID_HashTest ='1.2.643.2.2.30.0';
   OID_HashVerbaO ='1.2.643.2.2.30.1'; // ГОСТ Р 34.11-94, параметры по умолчанию */
   OID_HashVar_1 ='1.2.643.2.2.30.2';
   OID_HashVar_2 ='1.2.643.2.2.30.3';
   OID_HashVar_3 ='1.2.643.2.2.30.4';
Пример установки параметров:
Var pch: Pchar;
…
pch := OID_HashVar_3;

   if(not CryptSetHashParam(
        hHash,
        HP_OID,
        PByte(pch),
        0)) then
   begin
     raise TCryptException.Create(ceOtherCryptError);
   end;
…

По умолчанию КРИПТО-ПРО работает с параметрами 1.2.643.2.2.30.1, так что проблемы могут возникнуть, только если с помощью CryptSetHashParam(…,HP_OID,…) установить отличные от приведенных параметры.

3. Примечания.

  1. Почему я использую RtlSecureZeroMemory вместо RtlZeroMemory, описано (на английском), здесь.
    Саму эту функцию импортировать мне не удалось, поэтому я написал аналог.
    procedure RtlSecureZeroMemory(_ptr: PVoid; size: size_t);
        var i: Integer;
            ptr_c: Cardinal;
      begin
        //--- проверяем, доступна ли для записи вся переданная область
        if IsBadWritePtr(_ptr,size) then exit;
    
        ptr_c := Cardinal(_ptr);
    
        for I := 0 to size - 1 do
          PByte(ptr_c + i)^ := 0;
      end;
    

  2. Для решения возникающих вопросов по работе с КРИПТО-ПРО существует форум техподдержки
    Отвечают там не слишком скоро, зато ответы качественные.

  3. Исходные коды, прилагаемые к статье, находятся в процессе доработки. Но состояние их вполне рабочее.

  4. В ходе работы было выявлена неполнота заголовочных файлов wcrypt2.pas, некоторые не определенные там, но использовавшиеся в коде заголовки, структуры и константы определены в файле u_cryptcommon.pas, его можно посмотреть в архиве, прилагающемся к статье.

  5. Отдельный интерес представляет вопрос о различии между AT_KEYEXCHANGE и AT_SIGNATURE парами ключей. Причины введения именно такого разделения типов ключевых пар лично мне непонятны. Некоторые объяснения можно прочитать по ссылке (на английском)
    Правда, это объяснение относится только к провайдерам от Микрософт, но я думаю, что распространить его на провайдер КРИПТО-ПРО также возможно.

  6. Для запуска тестового приложения понадобится установленный провайдер КРИПТО-ПРО версии не ниже 2.0 и пара дискет) (или можно в реестр записать контейнеры).

4. Благодарности

Ins за плодотворные обсуждения, конструктивную критику материала и идею написать статью.

К материалу прилагаются файлы:


Смотрите также материалы по темам:
[Криптография]

 Обсуждение материала [ 14-02-2020 07:27 ] 8 сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования