CRYPTOAPI и ГОСТ алгоритмы

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Добрый день!
Пытаюсь получить Hash по ГОСТ алгоритму с помощью функций Cryptoapi.
Использую CryptoClType класс из:
cryptocl.clw
cryptocl.inc

На 4-ом шаге получаю ошибку 87 - Параметр задан неверно

Схематичный порядок действий:

Код: Выделить всё

 Module('advapi32.dll')
     CryptAcquireContext(*LONG hProv,<*CSTRING Container>,<*CSTRING Provider>,LONG ProviderType,LONG dwFlags),BYTE,RAW,PASCAL,NAME('CryptAcquireContextA')
     CryptCreateHash(LONG hProv, LONG AlgId,LONG hKey,LONG dwFlags,*LONG phHash),BYTE,RAW,PASCAL
     CryptHashData(ULONG hHash,LONG pbData,LONG dwDataLen,LONG dwFlags),BYTE,RAW,PASCAL
     CryptGetHashParam(LONG hHash,LONG dwParam,LONG pbData,*LONG pdwDataLen,LONG dwFlags),BYTE, RAW, PASCAL
  end

hHash               long
ParamBLOB           Group(_StrParam_BLOB).
hashlen             long
HashArr             BYTE,DIM(4),over(hashlen)
hashlensize         long(4)

self.ProviderType = PROV_GOST_2012_256 ! 80 
Algid = CALG_GR3411_2012_256  ! 32801

1. CryptAcquireContext(SELF.hCryptProv,,, SELF.ProviderType,CRYPT_VERIFYCONTEXT)

! Create an empty Hash
2. CryptCreateHash(SELF.hCryptProv,AlgId,0,0,hHash) 

! Hash the supplied Password
3. CryptHashData(hHash,ADDRESS(Password),PasswordLen,0) 

4. CryptGetHashParam(hHash,HP_HASHSIZE,ADDRESS(HashArr[1]),Hashlensize,0) 
!!! Здесь получаю ошибку 

ParamBLOB.ParamData &= NEW(STRING(hashlen))

5. CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0) 
А с такими параметрами прекрасно работает:
self.ProviderType = PROV_RSA_AES ! 24
Algid = CALG_SHA_256 ! 32780

И пример на С из пакета Cryptopro SDK нормально отрабатывает с ГОСТ алгоритмом.

В чем может быть ошибка? Что не нравится функции CryptGetHashParam ?
Может, кто то сталкивался с такой проблемой ?
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

Не знаю, что не так с CryptGetHashParam, но в следующей строке Вы фактически создаёте строку нулевой длины:
NEW(STRING(0))
С уважением, ДП
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Нет. При нормальной работе
CryptGetHashParam(hHash,HP_HASHSIZE,ADDRESS(HashArr[1]),Hashlensize,0)
В HashArr получаем размер буфера и соответственно в hashlen , т.к.
HashArr BYTE,DIM(4),over(hashlen)

Но в случае ГОСТ алгоритмов, до этого NEW() дело не доходит ) - выхожу по ошибке.
Для наглядности убрал код проверки.
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

Да, виноват, не заметил OVER.
Вообще гугл вот такую ссылку выдаёт на ошибку 87:
https://social.msdn.microsoft.com/Forum ... =vcgeneral
А в MSDN написано, что вся эта Crypt api устарела,.
С уважением, ДП
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Дед Пахом писал(а): 10 Ноябрь 2021, 17:51 А в MSDN написано, что вся эта Crypt api устарела,
Но в С работает )
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

Давайте C код посмотрим.
С уважением, ДП
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Код: Выделить всё

#include <stdio.h>
#ifdef _WIN32
#   include <windows.h>
#   include <wincrypt.h>
#else
#   include <stdlib.h>
#endif
#include <WinCryptEx.h>

static void HandleError(const char *s);

// Начало примера (не следует удалять данный комментарий, он используется 
// для автоматической сборки документации)
//--------------------------------------------------------------------
// Пример создания хэша из содержимого файла. Имя файла задается в 
// командной строке и является обязательным параметром.
// Замечание: под win32 рекомендуется использовать _s аналоги CRT функций.
//--------------------------------------------------------------------

#define BUFSIZE 1024
#define GR3411LEN  64

int main(int argc, char *argv[])
{
    //-------------------------------------------------------------
    // Объявление и инициализация переменных. 
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    FILE* hFile;
    BYTE rgbFile[BUFSIZE];
    DWORD cbRead = 0;
    BYTE rgbHash[GR3411LEN];
    DWORD cbHash = 0;
    CHAR rgbDigits[] = "0123456789abcdef";
    DWORD i;

    //--------------------------------------------------------------------
    // Проверка того, передано ли имя файла.
    if(argc != 2 || argv[1] == NULL)
    {
	HandleError("The file name is absent.\n");
    }

    //--------------------------------------------------------------------
    // Открытие файла.
    // if(!fopen_s(&hFile, argv[1], "r+b"))
    if(!(hFile = fopen(argv[1], "r+b" )))
    {
	HandleError("Error opening input file"); 
    }
    printf( "The file %s was opened\n", argv[1]);


    //--------------------------------------------------------------------
    // Получение дескриптора криптопровайдера.

    if(!CryptAcquireContext(
	&hProv,
	NULL,
	NULL,
	PROV_GOST_2012_256,
	CRYPT_VERIFYCONTEXT))
    {
	HandleError("CryptAcquireContext failed");
    }

    //--------------------------------------------------------------------
    // Создание пустого объекта функции хэширования.

    if(!CryptCreateHash(hProv, CALG_GR3411_2012_256, 0, 0, &hHash))
    {
	CryptReleaseContext(hProv, 0);
	HandleError("CryptCreateHash failed"); 
    }

    //--------------------------------------------------------------------
    // Чтение данных из файла и хэширование этих данных.

    do
    {
	cbRead = (DWORD)fread(rgbFile, 1, BUFSIZE, hFile);

	if (cbRead)
	{
	    if (!CryptHashData(hHash, rgbFile, cbRead, 0))
	    {
		CryptReleaseContext(hProv, 0);
		CryptDestroyHash(hHash);
		HandleError("CryptHashData failed");
	    }
	}
    }
    while(!feof(hFile));

    //--------------------------------------------------------------------
    // Получение параметра объекта функции хэширования.
    cbHash = GR3411LEN;
    
    if(!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
    {
	CryptDestroyHash(hHash);
	CryptReleaseContext(hProv, 0);
	HandleError("CryptGetHashParam failed"); 
    }

    printf("GR3411 hash of file %s is: ", argv[1]);
    for(i = 0; i < cbHash; i++)
    {
	printf("%c%c", rgbDigits[rgbHash[i] >> 4],
	    rgbDigits[rgbHash[i] & 0xf]);
    }
    printf("\n");

    //--------------------------------------------------------------------
    // Освобождение.
    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
    fclose(hFile);

    return S_OK;
}

// Конец примера 
// (не следует удалять данный комментарий, он используется 
//  для автоматической сборки документации)

//------------------------------------------------------------------------------
//  В этом примере используется функция HandleError, функция обработки
//  простых ошибок, для печати сообщения об ошибке в стандартный файл 
//  ошибок (stderr) и выхода из программы. 
//  В большинстве приложений эта функция заменяется другой функцией, 
//  которая выводит более полное сообщение об ошибке.
//------------------------------------------------------------------------------
void HandleError(const char *s)
{
    DWORD err = GetLastError();
    printf("Error number     : 0x%x\n", err);
    printf("Error description: %s\n", s);
    if(!err) err = 1;
    exit(err);
}
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Как в С сразу получить Hash , без предварительного получения размера, тоже не получается - та же ошибка

Код: Выделить всё

 hashlen = GR3411LEN
 ParamBLOB.ParamData &= NEW(STRING(hashlen))

 if ~CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0) then
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

Я вижу, что Вы передаёте HP_HASHSIZE, в C передаётся HP_HASHVAL. Вы говорили, что в C работает, теперь что не работает.
С уважением, ДП
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Исходник на С полностью рабочий.
Я говорил о программе на Clarion.
В кларионовском классе было реализовано через два вызова CryptGetHashParam(). Сначала получаем размер буфера, затем сам Hash.
Я попробовал реализовать в кларике, как в С - один вызов CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0),
но это не момогло.
Код на С я не трогал.
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

harry писал(а): 10 Ноябрь 2021, 18:47 CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0)
Здесь надо бы CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlensize,0)
С уважением, ДП
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

К сожалению, hashlensize вместо hashlen не помог. Да и, вроде, оба Long.
harry
Бывалый
Сообщения: 69
Зарегистрирован: 24 Февраль 2015, 14:16
Поблагодарили: 3 раза

CRYPTOAPI и ГОСТ алгоритмы

Сообщение harry »

Странно, что для типа криптопровайдера self.ProviderType = PROV_GOST_2012_256 такая проблема, а для PROV_RSA_AES и его алгоритмов норм.
Значит, типы параметров с точки зрения функций Cryptoapi описаны правильно ? Не нравится значение какого то параметра?
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

Оба long, только в одном размер буфера (4), а в другом то ли 0, то ли мусор.
С уважением, ДП
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

CRYPTOAPI и ГОСТ алгоритмы

Сообщение Дед Пахом »

Могу предположить, что буфер слишком маленький.
С уважением, ДП
Ответить