Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline nikandfor  
#1 Оставлено : 10 декабря 2019 г. 21:09:08(UTC)
nikandfor

Статус: Новичок

Группы: Участники
Зарегистрирован: 10.12.2019(UTC)
Сообщений: 2

Есть задача, взять ключ и данные, посчитать HMAC. Аналогичные операции проделать на другой машинке, платформе и языке программирования, и чтобы хеш сошёлся.

Нашел 2 константы на эту тему: CALG_GR3411_2012_256_HMAC_FIXEDKEY и CALG_GR3411_2012_256_HMAC.
Вторая, на сколько понял, для случаев когда ключем HMAC является сессионный ключ или тому подобное, но не сам ключ в чистом виде, соответственно, мне нужен первый вариант.

Собрал вот такой код:

Код:

// HCRYPTPROV hProv = ...

HCRYPTHASH hHash;
BOOL r_hash = CryptCreateHash(hProv, CALG_GR3411_2012_256_HMAC_FIXEDKEY, 0, 0, &hHash);
if (r_hash) {
    ret_set_error(ret, "create hash", GetLastError());
    goto error;
}

CRYPT_DATA_BLOB keyBlob;
keyBlob.cbData = 32;
keyBlob.pbData = (BYTE *)hmac_key;

// если тут вместо &keyBlob поставить просто 10, то если он хотя бы читал это, был бы сигфолт, а его нет
BOOL r = CryptSetHashParam(hProv, HP_HMAC_FIXEDKEY, (BYTE *)(&keyBlob), 0);
if (!r) {
    ret_set_error(ret, "set hmac key", GetLastError());
    goto error;
}


И неизменно получаю ошибку: set hmac key: The parameter is incorrect. [last error code: 0x57]

Другой вариант я тоже рассматривал
Код:

    HCRYPTKEY hKey;
    r_key = CryptImportKey(hProv, hmac_key, 32, 0, 0, &hKey);
    if (!r_key) {
        ret_set_error(&ret, "import HMAC key", GetLastError());
        goto error;
    }

    HCRYPTHASH hHash;
    r_hash = CryptCreateHash(hProv, CALG_GR3411_2012_256_HMAC, hKey, 0, &hHash);
    if (!r_hash) {
        ret_set_error(&ret, "create hash", GetLastError());
        goto error;
    }

так я получаю import HMAC key: Bad Data. [80090005]


Пробовал даже так. Это константа хедера публичного ключа. Так import HMAC key: The keyset is not defined. [80090019]
Код:

    BYTE fullkey[101] = {0x06, 0x20, 0x00, 0x00, 0x49, 0x2e, 0x00, 0x00, 0x4d, 0x41, 0x47, 0x31, 0x00, 0x02, 0x00, 0x00, 0x30, 0x13, 0x06,
                         0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02};

    memcpy(fullkey + 37, key, 32);

    HCRYPTKEY hKey;
    r_key = CryptImportKey(hProv, (BYTE *)fullkey, 37 + 32, 0, 0, &hKey);
    if (!r_key) {
        ret_set_error(&ret, "import HMAC key", GetLastError());
        goto error;
    }


Контекст получаю во всех случаях вот так.
Код:

    HCRYPTPROV hProv;
    r_context = CryptAcquireContext(&hProv, NULL, NULL, PROV_GOST_2012_256, CRYPT_VERIFYCONTEXT);
    if (!r_context) {
        ret_set_error(&ret, "acquire context", GetLastError());
        goto error;
    }


Подскажите, как нужно.

Отредактировано пользователем 11 декабря 2019 г. 9:54:16(UTC)  | Причина: Не указана

Offline not_x  
#2 Оставлено : 16 декабря 2019 г. 13:40:50(UTC)
not_x

Статус: Участник

Группы: Участники
Зарегистрирован: 27.06.2017(UTC)
Сообщений: 16
Российская Федерация

Здесь пример создания HMAC c алгоритмом SHA1
https://docs.microsoft.c...rogram--creating-an-hmac

Порядок действий примерно такой:


1. CryptCreateHash( .. CALG_GR3411_2012_256_HMAC, SecretKey, ... )
3. CryptHashData(...)
4 CryptGetHashParam (.. HP_HASHVAL)

Отредактировано пользователем 19 декабря 2019 г. 10:25:14(UTC)  | Причина: Ошибка

Offline not_x  
#3 Оставлено : 19 декабря 2019 г. 10:22:54(UTC)
not_x

Статус: Участник

Группы: Участники
Зарегистрирован: 27.06.2017(UTC)
Сообщений: 16
Российская Федерация

В SDK КриптоПро CSP 5.0 apdu_handle_2012.c



Импорт секрета см. из SIMPLBLOB https://www.cryptopro.ru....aspx?g=posts&t=2939 , https://www.cryptopro.ru....aspx?g=posts&t=3243

Тестовые значение см в "РЕКОМЕНДАЦИИ ПО СТАНДАРТИЗАЦИИ Р 50.1.113 2016"

Отредактировано пользователем 19 декабря 2019 г. 10:25:54(UTC)  | Причина: Не указана

Offline nikandfor  
#4 Оставлено : 19 декабря 2019 г. 16:56:36(UTC)
nikandfor

Статус: Новичок

Группы: Участники
Зарегистрирован: 10.12.2019(UTC)
Сообщений: 2

Спасибо, not_x, за ответы.

Первый пример я видел, там ключ через CryptDeriveKey делается, а мне надо из блоба. А Set HP_HMAC_INFO предназначен, на сколько я понял, для переопределения дефолтных inner и outer векторов.

Второй пример не содержит инициализацию masterKey, который, видимо тоже через CryptDeriveKey инициализируется.

Мне бы именно понять, как с CryptSetHashParam и HP_HMAC_FIXEDKEY нужно работать в реализации криптопро.
Offline not_x  
#5 Оставлено : 19 декабря 2019 г. 22:28:43(UTC)
not_x

Статус: Участник

Группы: Участники
Зарегистрирован: 27.06.2017(UTC)
Сообщений: 16
Российская Федерация

1. Генерится случайный ключ согласования.
2. На ключе согласования с учётом UKM шифруется masterKey, вычисляется ими-вставка, формируется SIMPLBLOB.
3. Импортируется SIMPLBLOB на ключе согласования и получаете дескриптор ключа секрета.

( в приведённых постах есть примеры кода).

4. На ключе секрета вычисляется HMAC( пример: HMAC_2012_256)

Естественно, контейнер криптопровайлера должен быть создан с корректным идентификатором.
Проверяется по тестовым значениям
CryptDeriveKey криптопро не рекомендует использовать.


P.S. Первоначально ввёл в заблуждение: на ГОСТ HMAC HP_HMAC_INFO не требуется.
Offline mel26  
#6 Оставлено : 7 апреля 2022 г. 13:27:16(UTC)
mel26

Статус: Новичок

Группы: Участники
Зарегистрирован: 17.05.2010(UTC)
Сообщений: 9
Откуда: Moscow

Встала такая же задача. Несколько часов курения всего подряд, получил работающий код ниже.
HMAC вычисляется в функции main.

Используется довольно грязный способ ручного формирования SIMPLE BLOB, но другого способа не нашёл.

Коллеги говорят, что на самом деле так делать ай-ай-ай :)

Спасибо паре примеров на этом форуме.

HMAC сошелся с реализацией BouncyCastle на Java

Код:


void HandleError(const char *s)
{
	DWORD err = GetLastError();
	printf("Error number     : 0x%x\n", err);
	printf("Error description: %s\n", s);

	getchar();

	if (!err) err = 1;
	exit(err);
}

static int fill_default_simpleblob(CRYPT_SIMPLEBLOB *blob)
{
	if (blob == NULL) {
		return 0;
	}

	/*BLOBHEADER*/
	blob->tSimpleBlobHeader.BlobHeader.bType = SIMPLEBLOB;
	blob->tSimpleBlobHeader.BlobHeader.bVersion = BLOB_VERSION; // 0x20 current.
	blob->tSimpleBlobHeader.BlobHeader.reserved = 0x0;
	blob->tSimpleBlobHeader.BlobHeader.aiKeyAlg = CALG_G28147; // CALG_G28147_IMIT; 

	blob->tSimpleBlobHeader.Magic = G28147_MAGIC;
	blob->tSimpleBlobHeader.EncryptKeyAlgId = CALG_G28147;

	return 1;
}

/** Magic value for EncryptionParamSet.
* Designated to represent DER-encoded ASN1-structure for GOST 28147 paramset.
* Probably it's corresponds to id-GostR3410-2001-CryptoPro-XchA-ParamSet.
*/
static const BYTE default_params[] = { 0x30, 0x09, 0x06, 0x07,
0x2A, 0x85, 0x03, 0x02,
0x02, 0x1F, 0x01 };


#define DBG_OUT(msg) fprintf(stderr, "MSG %s:%d:%s: %s\n", __FILE__, __LINE__, __FUNCTION__, msg);
#define DBG_OUT_E(msg) fprintf(stderr, "MSG %s:%d:%s: %s : 0x%X\n", __FILE__, __LINE__, __FUNCTION__, msg, GetLastError());

/**
* Converts raw key data to HCRYPTKEY suitable for later usage.
* @param hProvider must be exportable
* @param key raw key (rfc4357 6.1 CEK)
* @return  - HCRYPTKEY if success
*          - 0 if fails
*/
HCRYPTKEY get_CAPI_key_from_raw(HCRYPTPROV hProv, const unsigned char *key) {

	/// The idea is from here:  http://etutorials.org/Programming/secure+programming/Chapter+5.+Symmetric+Encryption/5.26+Creating+a+CryptoAPI+Key+Object+from+Raw+Key+Data/
	/// But GOST has a specific...
	HCRYPTKEY  resKey = 0;
	DWORD      dataLen = 0;

	// We decrement it by 4 due to 4 bytes alignment of BYTE bEncryptionParamSet[1] array.
	// @bug incompatible with x64?
	const size_t REAL_CRYPT_SIMPLEBLOB_LEN = sizeof(CRYPT_SIMPLEBLOB)
		+ sizeof(default_params) - 4;

	CRYPT_SIMPLEBLOB* keyBlob = NULL;

	keyBlob = (CRYPT_SIMPLEBLOB*)malloc(REAL_CRYPT_SIMPLEBLOB_LEN);
	if (!keyBlob) {
		HandleError("Can't allocate CRYPT_SIMPLEBLOB");
	}

	memset(keyBlob, 0, REAL_CRYPT_SIMPLEBLOB_LEN);

	fill_default_simpleblob(keyBlob);

	// key is a CEK rfc4357 6.1
	memcpy(keyBlob->bEncryptedKey, key, G28147_KEYLEN);
	memcpy(keyBlob->bEncryptionParamSet, default_params, sizeof(default_params));

	// Generate random KEK rfc4357 6.1.1.
	HCRYPTKEY kek;
	if (!CryptGenKey(hProv, CALG_G28147, CRYPT_EXPORTABLE, &kek))
	{
		HandleError("Can't generate KEK");
	}


	DWORD dparam = 0;

	dparam = ZERO_PADDING;

	if (!CryptSetKeyParam(kek, KP_PADDING, (BYTE*)&dparam, 0))
	{
		HandleError("Can't set ZERO_PADDING for generated KEK.");
	}

	/*  Well, let's assume UMK is always zeros...
	// Generate UKM rfc4357 6.1.1.
	if(!CryptGenRandom(hProvider, sizeof(keyBlob->bSV), keyBlob->bSV)){
	DBG_OUT_E("Can't generate UKM");
	goto done;
	}

	*/
	// Compute CEK_MAC rfc4357 6.1.2.
	HCRYPTKEY im_key;
	if (!CryptDuplicateKey(kek,    // from
		NULL, 0,  // two reserved
		&im_key)) // to
	{
		HandleError("Can't duplicate key for IMITO");
	}

	// Useless as UKV is always zeros, but still...
	// Set IV for IMITO
	if (!CryptSetKeyParam(
		im_key,
		KP_IV,
		keyBlob->bSV,
		0)) {
		HandleError("Can't set IV for IMITO");
	}

	HCRYPTHASH im = 0;
	if (!CryptCreateHash(hProv, CALG_G28147_IMIT, im_key, 0, &im))
	{
		HandleError("Can't create IMITO hash");
	}

	if (!CryptHashData(im, keyBlob->bEncryptedKey, G28147_KEYLEN, 0))
	{
		HandleError("Can't hash CEK");
	}

	DWORD imitLen = EXPORT_IMIT_SIZE;

	if (!CryptGetHashParam(im,
		HP_HASHVAL,
		keyBlob->bMacKey, // This is a CEK_MAC in RFC4357 6.1.2
		&imitLen, 0))
	{
		HandleError("Can't get CEK hash");
	}
	// END compute CEK_MAC


	// Encrypt key to CEK_ENC rfc4357 6.1.3.
	HCRYPTKEY enc_key;

	if (!CryptDuplicateKey(kek, 0, 0, &enc_key)) {
		HandleError("Can't dup KEK for encryption.");
	}

	dparam = CRYPT_MODE_ECB;
	if (!CryptSetKeyParam(enc_key, KP_MODE, (BYTE*)&dparam, 0)) {
		HandleError("Can't set ECB mode");
	}

	dataLen = G28147_KEYLEN;
	if (!CryptEncrypt(enc_key, 0, TRUE, 0, NULL, &dataLen, 0)) {
		HandleError("Can't detemine required buffer size.");
	}

	printf("Buffer size required: %d\n", dataLen);

	if (G28147_KEYLEN != dataLen) {
		HandleError("Required buffer size and G28147_KEYLEN mismatch");
	}

	if (!CryptEncrypt(enc_key, 0, TRUE, 0, keyBlob->bEncryptedKey, &dataLen, dataLen)) {
		HandleError("Can't encrypt raw key");
	}
	// END Encrypt key to CEK_ENC rfc4357 6.1.3.

	dparam = CALG_SIMPLE_EXPORT;
	if (!CryptSetKeyParam(kek, KP_ALGID, (BYTE *)& dparam, 0))
	{
		HandleError("Can't set SIMPLE_EXPORT param for KEK");
	}

	dataLen = REAL_CRYPT_SIMPLEBLOB_LEN;
	if (!CryptImportKey(hProv,
		(BYTE*)keyBlob,
		dataLen,
		kek,
		0,
		&resKey))
	{
		HandleError("Can't import key");
	}
	else {
		printf("Key is imported from raw value");
	}

done:

	if (!CryptDestroyKey(enc_key)) {
		DBG_OUT_E("Fail to destroy enc_key:");
	}

	if (!CryptDestroyKey(im_key)) {
		DBG_OUT_E("Fail to destroy im_key:");
	}

	if (!CryptDestroyKey(kek)) {
		DBG_OUT_E("Fail to destroy kek:");
	}

	free(keyBlob);
	return resKey;
}

#define GR3411LEN  64
int main()
{
	BYTE* data = new BYTE[6]{ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };

	HCRYPTPROV hProv;
	BYTE* rawKey = new BYTE[32]{ 0x2b, 0xf2, 0x26, 0xa4, 0xc8, 0x1f, 0x24, 0x90, 0xe0, 0xd9, 0x84, 0xd8, 0x4e, 0x57, 0xee, 0x80, 0x7a, 0x57, 0xc3, 0x77, 0xe9, 0xfa, 0x06, 0x45, 0x96, 0x6b, 0x9c, 0xab, 0x4b, 0xb3, 0x47, 0xe9 };

	DWORD cbHash = 0;

	BYTE rgbHash[GR3411LEN];
	CHAR rgbDigits[] = "0123456789abcdef";

	if (!CryptAcquireContext(
		&hProv,
		NULL,
		NULL,
		PROV_GOST_2012_256,
		CRYPT_VERIFYCONTEXT))
	{
		HandleError("CryptAcquireContext failed");
	}
	HCRYPTKEY hmacKey = get_CAPI_key_from_raw(hProv, rawKey);

	HCRYPTHASH hHash;
	if (!CryptCreateHash(hProv, CALG_GR3411_2012_256_HMAC, hmacKey, 0, &hHash)) {
		HandleError("CryptCreateHash failed");
	}

	if (!CryptHashData(hHash, data, 6, 0))
	{
		CryptReleaseContext(hProv, 0);
		CryptDestroyHash(hHash);
		HandleError("CryptHashData failed");
	}

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

	printf("HMAC is: ");
	for (int i = 0; i < cbHash; i++)
	{
		printf("%c%c", rgbDigits[rgbHash[i] >> 4],
			rgbDigits[rgbHash[i] & 0xf]);
	}
	printf("\n");

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

Отредактировано пользователем 7 апреля 2022 г. 13:28:29(UTC)  | Причина: Не указана

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