Страница 1 из 2
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 17:17
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 ?
Может, кто то сталкивался с такой проблемой ?
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 17:32
Дед Пахом
Не знаю, что не так с CryptGetHashParam, но в следующей строке Вы фактически создаёте строку нулевой длины:
NEW(STRING(0))
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 17:43
harry
Нет. При нормальной работе
CryptGetHashParam(hHash,HP_HASHSIZE,ADDRESS(HashArr[1]),Hashlensize,0)
В HashArr получаем размер буфера и соответственно в hashlen , т.к.
HashArr BYTE,DIM(4),over(hashlen)
Но в случае ГОСТ алгоритмов, до этого NEW() дело не доходит ) - выхожу по ошибке.
Для наглядности убрал код проверки.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 17:51
Дед Пахом
Да, виноват, не заметил OVER.
Вообще гугл вот такую ссылку выдаёт на ошибку 87:
https://social.msdn.microsoft.com/Forum ... =vcgeneral
А в MSDN написано, что вся эта Crypt api устарела,.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 17:53
harry
Дед Пахом писал(а): 10 Ноябрь 2021, 17:51
А в MSDN написано, что вся эта Crypt api устарела,
Но в С работает )
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 17:54
Дед Пахом
Давайте C код посмотрим.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 18:14
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);
}
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 18:18
harry
Как в С сразу получить Hash , без предварительного получения размера, тоже не получается - та же ошибка
Код: Выделить всё
hashlen = GR3411LEN
ParamBLOB.ParamData &= NEW(STRING(hashlen))
if ~CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0) then
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 18:40
Дед Пахом
Я вижу, что Вы передаёте HP_HASHSIZE, в C передаётся HP_HASHVAL. Вы говорили, что в C работает, теперь что не работает.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 18:47
harry
Исходник на С полностью рабочий.
Я говорил о программе на Clarion.
В кларионовском классе было реализовано через два вызова CryptGetHashParam(). Сначала получаем размер буфера, затем сам Hash.
Я попробовал реализовать в кларике, как в С - один вызов CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0),
но это не момогло.
Код на С я не трогал.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 18:59
Дед Пахом
harry писал(а): 10 Ноябрь 2021, 18:47
CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlen,0)
Здесь надо бы CryptGetHashParam(hHash,HP_HASHVAL,ADDRESS(ParamBLOB.ParamData),hashlensize,0)
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 19:27
harry
К сожалению, hashlensize вместо hashlen не помог. Да и, вроде, оба Long.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 19:38
harry
Странно, что для типа криптопровайдера self.ProviderType = PROV_GOST_2012_256 такая проблема, а для PROV_RSA_AES и его алгоритмов норм.
Значит, типы параметров с точки зрения функций Cryptoapi описаны правильно ? Не нравится значение какого то параметра?
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 19:39
Дед Пахом
Оба long, только в одном размер буфера (4), а в другом то ли 0, то ли мусор.
CRYPTOAPI и ГОСТ алгоритмы
Добавлено: 10 Ноябрь 2021, 19:41
Дед Пахом
Могу предположить, что буфер слишком маленький.