« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
    Популярное
Функция AccessResource

Галерея компонентов

Domain Name Service - cлужба Доменных Имен

Выход из AutoCAD

Доступ к реестру средствами API

Доходы и расходы семьи

Запуск Linux-приложений из FreeBSD

Списки

Практический AJAX: что делать с кнопкой «назад» в браузерах

Упрощаем разработку сайтов с JavaScript




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 182
Пользователей: 0

Статьи:: Delphi :: Разные статьи :: Windows и Delphi для защиты секретов 2



отправить ссылку другу версия для печати  Обсудить на форуме

Windows и Delphi для защиты секретов 2



Delphi и Windows API для защиты секретов

Windows и Delphi для защиты секретов

Как реализовать методы криптографической защиты информации при помощи подручных средств - Windows и Delphi

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

Проблема распределения ключей

В прошлый раз при помощи CryptoAPI мы решали такую "классическую" задачу как шифрование на основе пароля. Напомним, что пароль использовался для создания ключа шифрования какого-либо симметричного алгоритма. В таком случае расшифровать файл может лишь тот, кто знает пароль. А значит, для обеспечения конфиденциальности нужно держать пароль в строжайшем секрете - желательно, чтобы его знали лишь отправитель и получатель информации. (А еще лучше, если отправитель и получатель - одно и то же лицо.)

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

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

 

Спасительный способ, позволяющий шифровать сообщения, обмениваясь ключами по открытым каналам связи, был придуман в середине 70-х годов прошлого столетия, а в начале восьмидесятых появился первый реализующий его алгоритм - RSA. Теперь пользователь может сгенерировать два связанных между собой ключа - ключевую пару. Один из этих ключей по несекретным каналам рассылается всем, с кем пользователь хотел бы обмениваться конфиденциальными сообщениями (рис. 1). Этот ключ называют открытым (англ. public key). Зная открытый ключ пользователя, можно зашифровать адресованное ему сообщение, но вот расшифровать его позволяет лишь вторая часть ключевой пары - закрытый ключ (private key). При этом открытый ключ не дает "практической" возможности вычислить закрытый: такая задача, хоть и разрешима в принципе, но при достаточно большом размере ключа требует многих лет машинного времени. Для сохранения конфиденциальности получателю необходимо лишь хранить в строгом секрете свой закрытый ключ, а отправителю - убедиться, что имеющийся у него открытый ключ действительно принадлежит адресату.

 

Так как для шифрования и расшифровки используются различные ключи, алгоритмы такого рода назвали асимметричными. Наиболее существенным их недостатком является низкая производительность - они примерно в 100 раз медленнее симметричных алгоритмов. Поэтому были созданы криптографические схемы, использующие преимущества как симметричных, так и асимметричных алгоритмов (рис. 2):

  • для шифрования файла или сообщения используется быстрый симметричный алгоритм, причем ключ шифрования генерируется случайным образом с обеспечением "хороших" статистических свойств;
  • небольшой по размерам симметричный ключ шифрования шифруется при помощи асимметричного алгоритма с использованием открытого ключа адресата и в зашифрованном виде пересылается вместе с сообщением;
  • получив сообщение, адресат своим закрытым ключом расшифровывает симметричный ключ, а с его помощью - и само сообщение.

    Описанная схема реализована и в CryptoAPI.

     

    Целостность и аутентичность информации

    Как удостовериться в том, что пришедшее сообщение действительно отправлено тем, чье имя стоит в графе "отправитель"? Асимметричные схемы шифрования дают нам элегантный способ аутентификации. Если отправитель зашифрует сообщение своим закрытым ключом, то успешное расшифровывание убедит получателя в том, что послать корреспонденцию мог только хозяин ключевой пары, и никто иной (рис. 3). При этом расшифровку может выполнить любой, кто имеет открытый ключ отправителя. Ведь наша цель - не конфиденциальность, а аутентификация.

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

  • аутентичность сообщения - создать подпись на основе закрытого ключа мог только его хозяин;
  • целостность данных - легко вычислить хеш-значение полученного сообщения и сравнить его с тем, которое хранится в подписи: если значения совпадают, значит, сообщение не было изменено злоумышленником после того, как отправитель его подписал.

    Таким образом, асимметричные алгоритмы позволяют решить две непростые задачи: обмена ключами шифрования по открытым каналам связи и подписи сообщения. Чтобы воспользоваться этими возможностями, нужно сгенерировать и сохранить две ключевые пары - для обмена ключами и для подписей. В этом нам поможет CryptoAPI.

     

    Контейнеры ключей

    Каждый криптопровайдер располагает базой данных, в которой хранятся долговременные ключи пользователей. База данных содержит один или более контейнеров ключей (рис. 4). Пользователь может создать несколько контейнеров с различными именами (именем контейнера по умолчанию является имя пользователя в системе).

    Подключение к контейнеру производится одновременно с получением контекста криптопровайдера при вызове функции CryptAcquireContext - имя контейнера ключей передается функции вторым ее аргументом. Если второй аргумент содержит пустой указатель (nil), то используется имя по умолчанию, т. е. имя пользователя. В том случае, если доступ к контейнеру не нужен, можно передать в последнем аргументе функции флаг CRYPT_VERIFYCONTEXT; при необходимости создать новый контейнер используется флаг CRYPT_NEWKEYSET; а для удаления существующего контейнера вместе с хранящимися в нем ключами - CRYPT_DELETEKEYSET.

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

    Создание ключевых пар

    После создания контейнера ключей необходимо сгенерировать ключевые пары обмена ключами и подписи. Эту работу в CryptoAPI выполняет функция CryptGenKey (провайдер, алгоритм, флаги, ключ):

  • провайдер - дескриптор криптопровайдера, полученный в результате обращения к функции CryptAcquireContext;
  • алгоритм - указывает, какому алгоритму шифрования будет соответствовать создаваемый ключ. Информация об алгоритме, таким образом, является частью описания ключа. Каждый криптопровайдер использует для обмена ключами и подписи строго определенные алгоритмы. Так, провайдеры типа PROV_RSA_FULL, к которым относится и Microsoft Base Cryptographic Provider, реализуют алгоритм RSA. Но при генерации ключей знать это не обязательно: достаточно указать, какой ключ мы собираемся создать - обмена ключами или подписи. Для этого используются мнемонические константы AT_KEYEXCHANGE и AT_SIGNATURE;
  • флаги - при создании асимметричных ключей управляет их размером. Используемый нами криптопровайдер позволяет генерировать ключ обмена ключами длиной от 384 до 512 бит**, а ключ подписи - от 512 до 16384 бит. Чем больше длина ключа, тем выше его надежность, поэтому трудно найти причины для использования ключа обмена ключами длиной менее 512 бит, а длину ключа подписи не рекомендуется делать меньше 1024 бит**. По умолчанию криптопровайдер создает оба ключа длиной 512 бит. Необходимую длину ключа можно передать в старшем слове параметра флаги;
  • ключ - в случае успешного завершения функции в этот параметр заносится дескриптор созданного ключа.

     

    Рассмотрим пример создания ключевых пар при помощи формы, показанной на рис. 5. В поле "Контейнер" можно указать имя контейнера ключей; если оставить это поле пустым, будет использован контейнер по умолчанию. Назначение остальных элементов управления должно быть интуитивно понятным. После генерации ключа в memo-поле выводится отчет о его параметрах. Для этого используется функция CryptGetKeyParam (ключ, параметр, буфер, размер, флаги). Чтобы получить информацию о требуемом параметре, нужно через второй аргумент функции передать соответствующую константу: KP_ALGID - идентификатор алгоритма, KP_KEYLEN - размер ключа, и т. д. Ниже приведен текст процедуры генерации ключей без операторов обработки ошибок:

    procedure TGenerateForm.OKBtnClick(Sender: TObject);
    var cont: PChar;
    err: string;
    hProv: HCRYPTPROV;
    KeyExchKey, SignKey: HCRYPTKEY;
    flag, keyLen: DWORD;
    begin
    {если ни один ключ не выбран - выход}
    if not (KEKCheckBox.Checked or SKCheckBox.Checked) then exit;
    {"считываем" имя контейнера}
    if length(ContainerEdit.Text) = 0
    then cont := nil
    else
    begin
    err := ContainerEdit.Text;
    cont := StrAlloc(length(err) + 1);
    StrPCopy(cont, err);
    end;
    CryptAcquireContext(@hProv, cont, nil, PROV_RSA_FULL, 0);
    {генерация ключа обмена ключами (Key Exchange Key)}
    if KEKCheckBox.Checked then
    begin
    {"считываем" длину ключа и помещаем ее в
    старшее слово параметра ФЛАГИ}
    keyLen := strtoint(KeyExchLenEdit.text);
    flag := keyLen shl 16;
    if not CryptGenKey(hProv, AT_KEYEXCHANGE, flag, @KeyExchKey) then
    begin
    јобработка ошибокј
    end
    else
    begin
    ReportMemo.Lines.Add('');
    ReportMemo.Lines.Add('Создан ключ обмена ключами:');
    flag := 4;
    if not CryptGetKeyParam(KeyExchKey, KP_KEYLEN, @keyLen, @flag, 0) then
    begin
    јобработка ошибокј
    end
    else ReportMemo.Lines.Add(' длина ключа - ' + inttostr(keyLen));
    flag := 4;
    if not CryptGetKeyParam(KeyExchKey, KP_ALGID, @keyLen, @flag, 0) then
    begin
    јобработка ошибокј
    end
    else ReportMemo.Lines.Add(' алгоритм - ' + algIDtostr(keyLen));
    {функция algIDtostr здесь не приводится. Она состоит из единственного
    оператора case, отображающего целый идентификатор алгоритма в строку}
    end;
    end;
    {генерация ключа подписи (Signature Key)}
    if SKCheckBox.Checked then
    begin
    јвыполняется аналогично генерации ключа обмена ключамиј
    end;
    CryptReleaseContext(hProv, 0);
    end;
     

    Обмен ключами

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

  • PUBLICKEYBLOB - используется для сохранения открытых ключей. Поскольку открытые ключи не являются секретными, они сохраняются в незашифрованном виде;
  • PRIVATEKEYBLOB - используется для сохранения ключевой пары целиком (открытого и закрытого ключей). Эти данные являются в высшей степени секретными, поэтому сохраняются в зашифрованном виде, причем для шифрования используется сеансовый ключ (и, соответственно, симметричный алгоритм);
  • SIMPLEBLOB - используется для сохранения сеансовых ключей. Для обеспечения секретности данные ключа шифруются с использованием открытого ключа получателя сообщения.

    Экспорт ключей в CryptoAPI выполняется функцией CryptExportKey (экспортируемый ключ, ключ адресата, формат, флаги, буфер, размер буфера):

  • экспортируемый ключ - дескриптор нужного ключа;
  • ключ адресата - в случае сохранения открытого ключа должен быть равен нулю (данные не шифруются);
  • формат - указывается один из возможных форматов экспорта (PUBLICKEYBLOB, PRIVATEKEYBLOB, SIMPLEBLOB);
  • флаги - зарезервирован на будущее (должен быть равен нулю);
  • буфер - содержит адрес буфера, в который будет записан ключевой BLOB (Binary Large OBject - большой двоичный объект);
  • размер буфера - при вызове функции в этой переменной должен находиться доступный размер буфера, а по окончании работы в нее записывается количество экспортируемых данных. Если размер буфера заранее не известен, то функцию нужно вызвать с параметром буфер, равным пустому указателю, тогда размер буфера будет вычислен и занесен в переменную размер буфера.

     

    Экспорт ключевой пары целиком, включая и закрытый ключ, может понадобиться для того, чтобы иметь возможность подписывать документы на различных компьютерах (например, дома и на работе), или для сохранения страховочной копии. В этом случае нужно создать ключ шифрования на основании пароля (см. "К+П", № 10/2002) и передать дескриптор этого ключа в качестве второго параметра функции CryptExportKey.

    Запросить у криптопровайдера дескриптор самого' экспортируемого ключа позволяет функция CryptGetUserKey (провайдер, описание ключа, дескриптор ключа). Описание ключа - это либо AT_KEYEXCHANGE, либо AT_SIGNATURE.

    Экспорт асимметричных ключей во всем возможном многообразии можно осуществить при помощи формы, показанной на рис. 6.



    Ниже приведены наиболее важные фрагменты программы:

    procedure TExportForm.OKBtnClick(Sender: TObject);
    var cont: PChar;
    err: string;
    hProv: HCRYPTPROV;
    key, expKey: HCRYPTKEY;
    pbuf: PBYTE;
    buflen: DWORD;
    f: file;
    hash: HCRYPTHASH;
    begin
    {если ни один ключ не выбран - выход}
    if not (KEKCheckBox.Checked or SKCheckBox.Checked) then exit;
    {если нужен пароль, т.е. экспортируется ключевая пара целиком}
    if PasswEdit.Enabled and (PasswEdit.Text <> Passw2Edit.Text) then
    begin
    MessageDlg('Ошибка при вводе пароля! Повторите ввод.', mtError, [mbOK], 0);
    exit;
    end;
    …
    "считываем" имя контейнера и подключаемся к криптопровайдеру
    …
    если нужен ключ шифрования - создаем его на основании пароля
    …
    {ключ обмена ключами}
    if KEKCheckBox.Checked then
    repeat
    {получаем дескриптор ключа}
    CryptGetUserKey(hProv, AT_KEYEXCHANGE, @key);
    {пытаемся определить размер буфера для экспорта ключа}
    if (WhatRadioGroup.ItemIndex = 0) then
    CryptExportKey(key, 0, PUBLICKEYBLOB, 0, nil, @bufLen)
    else CryptExportKey(key, expKey, PRIVATEKEYBLOB, 0, nil, @bufLen);
    GetMem(pbuf, bufLen);
    {экспортируем данные}
    if (WhatRadioGroup.ItemIndex = 0) then
    CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pbuf, @bufLen)
    else CryptExportKey(key, expKey, PRIVATEKEYBLOB, 0, pbuf, @bufLen);
    {освобождаем дескриптор ключа обмена ключами
    (сам ключ при этом не уничтожается)}
    CryptDestroyKey(key);
    SaveDialog1.Title := 'Укажите файл для сохранения ключа обмена ключами';
    if SaveDialog1.Execute then
    begin
    AssignFile(f, SaveDialog1.FileName);
    rewrite(f, 1);
    BlockWrite(f, pbuf^, bufLen);
    CloseFile(f);
    MessageDlg('Ключ обмена ключами успешно сохранен', mtInformation, [mbOK], 0);
    end;
    until true; {KeyExchange}
    {ключ подписи}
    if SKCheckBox.Checked then
    repeat
    јаналогично ключу обмена ключамиј
    until true; {Signature}
    …
    если создавался ключ на основании пароля - уничтожаем его,
    после чего освобождаем контекст криптопровайдера
    …
    end;
     

    Экспортированные таким образом открытые части ключей понадобятся нам для проверки подписи и расшифровки сеансового ключа.

    Импорт ключевых пар во вновь созданный контейнер - это самостоятельная процедура. Необходимо запросить у пользователя название контейнера и пароль, подключиться к провайдеру, создать на основании пароля ключ, считать из файла импортируемые данные в буфер, после чего воспользоваться функцией CryptImportKey (провайдер, буфер, длина буфера, ключ для расшифровки, флаги, импортируемый ключ). Если нужно обеспечить возможность экспорта импортируемой ключевой пары впоследствии, то в параметре флаги необходимо передать значение CRYPT_EXPORTABLE; в противном случае вызов для данной ключевой пары функции CryptExportKey приведет к ошибке.

     

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

    Электронная цифровая подпись

     

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

    Подписать вычисленный хеш в CryptoAPI позволяет функция CryptSignHash (хеш, описание ключа, комментарий, флаги, подпись, длина подписи). Вторым параметром может быть либо AT_KEYEXCHANGE, либо AT_SIGNATURE (в нашем случае логичнее использовать ключ подписи). Третий параметр в целях безопасности настоятельно рекомендуется оставлять пустым (nil). Флаги в настоящее время также не используются - на месте этого аргумента должен быть нуль. Готовую электронную подпись функция запишет в буфер, адрес которого содержится в предпоследнем параметре, последний же параметр будет содержать длину подписи в байтах.

     


    procedure TSigningForm.SignBtnClick(Sender: TObject);
    var cont: PChar;
    err: string;
    hProv: HCRYPTPROV;
    key: HCRYPTKEY;
    alg: ALG_ID;
    hash: HCRYPTHASH;
    infile, outfile: file;
    size: DWORD;
    buf: array [0..511] of byte;
    signature: PBYTE;
    begin
    {проверка существования выбранного файла}
    if not FileExists(DataNameEdit.Text) then
    begin
    MessageDlg('Неверное имя файла!', mtError, [mbOK], 0);
    exit;
    end;
    AssignFile(infile, DataNameEdit.Text);
    …
    "считываем" имя контейнера и подключаемся к нему
    …
    case HashRadioGroup.ItemIndex of
    0: alg := CALG_MD5;
    1: alg := CALG_SHA;
    end;
    CryptCreateHash(hProv, alg, 0, 0, @hash);
    SaveDialog1.Title := 'Задайте имя файла для хранения подписанных данных';
    if SaveDialog1.Execute then
    begin
    AssignFile(outfile, SaveDialog1.FileName);
    rewrite(outfile, 1);
    {записываем в файл идентификатор алгоритма хеширования}
    BlockWrite(outfile, alg, 4);
    reset(infile, 1);
    size := FileSize(infile);
    {записываем размер подписываемых данных}
    BlockWrite(outfile, size, 4);
    {пишем сами данные и вычисляем хеш:}
    while not eof(infile) do
    begin
    BlockRead(infile, buf, 512, size);
    BlockWrite(outFile, buf, size);
    CryptHashData(hash, @buf, size, 0);
    end;
    CloseFile(infile);
    {выясняем размер подписи}
    CryptSignHash(hash, AT_SIGNATURE, nil, 0, nil, @size);
    {создаем подпись}
    GetMem(signature, size);
    CryptSignHash(hash, AT_SIGNATURE, nil, 0, signature, @size);
    BlockWrite(outfile, size, 4);
    BlockWrite(outfile, signature^, size);
    CloseFile(outfile);
    end;
    …
    уничтожаем хеш-объект и освобождаем контекст
    …
    end;
     

    Чтобы проверить правильность подписи, получатель подписанного сообщения должен иметь файл с открытым ключом подписи отправителя. В процессе проверки подписи этот ключ импортируется внутрь криптопровайдера. Проверка выполняется функцией CryptVerifySignature (хеш, подпись, длина подписи, открытый ключ, комментарий, флаги). О последних двух аргументах можно сказать то же, что и о параметрах комментарий и флаги функции CryptSignHash, назначение же остальных должно быть понятно. Если подпись верна, функция возвращает true. Значение false в качестве результата может свидетельствовать либо о возникновении ошибки в процессе проверки, либо о том, что подпись оказалась неверной. В последнем случае функция GetLastError вернет ошибку NTE_BAD_SIGNATURE. Для примера приведем наиболее значимые фрагменты программы проверки подписи:

    procedure TMainForm.VerifyItemClick(Sender: TObject);
    var err: string;
    hProv: HCRYPTPROV;
    key: HCRYPTKEY;
    alg: ALG_ID;
    hash: HCRYPTHASH;
    infile: file;
    size, test, textsize: DWORD;
    buf: PBYTE;
    signature, signkey: PBYTE;
    begin
    …
    получаем контекст криптопровайдера
    …
    OpenDialog1.Title := 'Укажите файл с подписанными данными';
    if OpenDialog1.Execute then
    begin
    AssignFile(infile, OpenDialog1.FileName);
    reset(infile, 1);
    {считываем идентификатор алгоритма хеширования}
    BlockRead(infile, alg, 4);
    {считываем размер подписанных данных и сами данные}
    BlockRead(infile, textsize, 4);
    GetMem(buf, textsize);
    BlockRead(infile, buf^, textsize, test);
    if test < textsize then
    begin
    MessageDlg('Неверный формат файла! Процесс прерван.', mtError, [mbOK], 0);
    exit;
    end;
    {считываем размер подписи и саму подпись}
    BlockRead(infile, test, 4);
    GetMem(signature, test);
    BlockRead(infile, signature^, test);
    CloseFile(infile);
    end
    else exit;
    …
    создаем хеш-объект и хешируем данные
    …
    OpenDialog1.Title := 'Укажите файл с открытым ключом подписи';
    if OpenDialog1.Execute then
    begin
    AssignFile(infile, OpenDialog1.FileName);
    reset(infile, 1);
    size := FileSize(infile);
    GetMem(signkey, size);
    BlockRead(infile, signkey^, size);
    CloseFile(infile);
    end
    else exit;
    {импортируем открытый ключ подписи отправителя}
    CryptImportKey(hProv, signkey, size, 0, 0, @key);
    FreeMem(signkey, size);
    {проверяем подпись}
    if CryptVerifySignature(hash, signature, test, key, nil, 0) then
    begin
    MessageDlg('Подпись верна.', mtInformation, [mbOK], 0);
    {сохраняем подписанные данные}
    SaveDialog1.Title := 'Укажите имя файла для сохранения данных';
    if SaveDialog1.Execute then
    begin
    AssignFile(infile, SaveDialog1.FileName);
    rewrite(infile, 1);
    BlockWrite(infile, buf^, textsize);
    CloseFile(infile);
    end;
    end
    else
    begin
    case int64(GetLastError) of
    NTE_BAD_SIGNATURE: err := 'Подпись неверна!';
    {обработка других ошибок}
    else err := 'Ошибка при проверке подписи: Unknown error';
    end;
    MessageDlg(err, mtError, [mbOK], 0);
    end;
    …
    уничтожаем хеш-объект и импортированный ключ
    и освобождаем контекст криптопровайдера
    …
    end;
     



  • Рубрика: Разные статьи




    HTML 5: пять вещей вызывающих особый интер....

    Html

    HTML 5 — это грядущее обновление гипертекстового языка разметки, основного способа создания контента для размещения его во всемирной паутине. Разработка HTML остановилась в 1999 году, на версии HTML 4.01 и с тех пор web-содержимое изменилось так, что текущие спецификации HTML перестали соответствовать сегодняшним требованиям. HTML 5 нацелен на то, чтобы увеличить функциональную совместимость HTML и соответствовать растущим требованиям разнообразного и смешанного web-контента. HTML 5 так же нацелен на устранение недостатков четвертой версии. В этой статье мы взглянем на 5 новых интересных вещей в HTML 5.


    Подробнее... | Рубрика: Html | Добавлено: 22.12.2008

    asp.net: ListView с разных сторон.

    .NET компоненты

    Элемент управления ListView был представлен в .Net Framework 3.5 как замена устаревшему GridView. Новый элемент имеет более расширенный функционал, чем его предшественник, но в тоже время лишен некоторых внутренних механизмов, что впрочем целиком следствие из расширенной универсальности ListView. Среди отличий ListView и GridView можно назвать и гибкую настройку разметки, что позволяет выводить данные не только в табличном виде, но и вообще в любом каком пожелает программист. Благодаря шаблонам ItemTemplate, EditItemTemplate, InsertItemTeplate можно настроить внешний вид при любом из состояний ListView: редактировании или выборе элемента.


    Подробнее... | Рубрика: .NET компоненты | Добавлено: 22.12.2008

    Создание кросс-таб отчета в Stimulsoft Rep....

    .NET компоненты

    Компания Стимулсофт предоставляет для разработчиков мощный набор инструментов для создания отчетов для Microsoft Visual Studio .Net 2005 и 2008; эти инструменты доступны как для Windows Forms, так и для Web Forms. Это генератор отчетов Stimulsoft Reports.Net. Генератор отчетов Stimulsoft Reports.Net имеет ряд особенностей: простая работа с дизайнером отчетов, полная поддержка экспорта в PDF, Word, Excel и многие другие форматы. Crystal Report и Microsoft Reporting Service – очень хорошие программные продукты для повседневной работы, но, если Вам необходимо создать отчеты с поддержкой кросс-табов, drill down, Ajax, штрих-кодов и возможностью подключения одновременно более одного источника данных, то Stimulsoft Reports.Net поможет Вам сэкономить массу времени. Также, данный генератор отчетов позволяет пользователям создавать свои собственные отчеты любой сложности. И все эти особенности делают Stimulsoft Reports.Net хорошим выбором в сфере программных продуктов для Business Intelligence.


    Подробнее... | Рубрика: .NET компоненты | Добавлено: 22.12.2008

    Остальные статьи:

    VivaMP - инструмент для OpenMP
    Создаем контекстно-зависимое WPF-приложени...
    Windows Vista SP2: что внутри и что важно?
    Вышел MySQL 5.1.30, первый стабильный рели...
    Тестирование параллельных программ
    Архитектура AMD64 (EM64T)
    Платформа 2009. Определяя будущее
    Windows Vista Bridge Sample Library - упра...
    Оптимизация 64-битных программ
    Подгрузка через AJAX HTML-кода, содержащег...
    Обзор нового релиза самой мощной Ajax библ...
    Firebug 1.3 и 1.4 alpha — что нового и инт...
    Релиз Microsoft Silverlight 2.0. Что новог...
    XML документация в C#
    Курсоры в MySQL 5
    Microsoft опубликовала подробности о сесси...
    Microsoft делится подробностями о том, что...
    Тестируем новый javascript от нового брауз...
    MySQL Query Cache
    Использование провайдеров компиляции в As...


    Цитата дня (все,добавить):

    Портал фрилансеров

    работа на дому


        Рубрикатор

    Программирование

    C/С++
    Обучение
    Windows API
    XAML
    Моделирование
    Паттерны
    Visual Basic 7 .NET
    WxWidgets
    Функции WinApi
    Функции С++
    Разработка под Mac OS
    Eiffel
    Visual Studio 2008
    UI дизайн
    Алгоритмы
    Конкурсные статьи
    Turbo Pascal
    Visual Studio
    CASE-средства
    Visual Studio 2005
    Без VCL
    Delphi
    Тех. документация
    Тестирование
    Software Testing
    ООП
    TCP/IP
    Google Android
    Windows Installer
    .NET Framework
    Драйвера
    C# C Sharp
    Справка
    Проектирование
    Информ. системы
    Visual Basic
    Assembler
    Оптимизация кода
    Gtk+
    Компоненты
    Реинжиниринг
    Управление проектами
    Extreeme programming
    Lotus Notes
    Алгебраическое проектирование


    Интернет технологии

    PHP
    Perl
    ASP
    WAP
    Cookies
    SSI
    CGI
    Web Servers
    VB Script
    DNS
    CSS
    XML
    Html
    Java Script
    Java2ME
    Firewall
    Flash
    .htaccess
    Apache
    VRML
    Протоколы
    Поисковые системы
    Технология JAVA
    Учебник по PHP
    Учебник по JavaScript
    Учебник по XML
    Java Q&A
    AJAX
    DHTML
    XHTML
    Dreamweaver
    Web 2.0
    Python
    Вебмастеру
    Cisco
    Ruby on Rails
    Silverlight

    Базы данных

    Access
    InterBase
    MySQL
    Oracle
    ADO .NET
    Основы SQL
    Учебник по Access 2002
    MS
    Microsoft FoxPro
    Доступ к данным
    XML в MS SQL Server 2000
    ODBC и MyODBC
    Обучение
    Caché
    DB2
    PostgresSQL
    Sybase
    Теория
    Хранилища данных
    Безопасность
    Реляционные данные
    MySQL и mSQL

    Остальное:

    Разное
    Обзоры книг
    Безопасность
    Графика и дизайн
    Юмор
    Linux
    Фракталы
    Microsoft Axapta
    Многоядерность
    Сети
    Microsoft Office
    Работа
    MS-DOS
    Криптография
    Графика и игроделание
    Новости SDK
    Системы защиты
    Учебник по AutoCad
    CVS
    Windows XP
    Windows Server 2003
    Windows Vista
    Windows 7
    Мероприятия