16.12.2004 15:56:20ГОСТ28147 и режим CBC Ответов: 6
max
Насколько я понял, ГОСТ28147 не должен поддерживать режим CBC (в ГОСТ он просто не описан).
В CryptoPro CBC реализован (CryptSetKeyParam работает), как это согласуется с ГОСТ ?
 
Ответы:
17.12.2004 12:47:10Bor1
В ГОСТ 28147, вообще говоря, не описаны ни ECB, ни CFB, ни OFB(CNT). Речь может идти только о аналогичных режимах. CBC в провайдере КриптоПро CSP реализован как в CBC на DES преобразовании.

Режим блочный.
Зашифрование.
На 0 шаг блок зацепления передается извне.
На i-шаге (i>=0)
1. извлекается i-й блок данных;
2. побитово складывается с блоком зацепления;
3. подается на шифратор ГОСТ 28147
4. выход шифратора -> шифрованный i-й блок.
5. выход шифратора -> блок зацепления

Расшифрование:
на 0 шаг блок зацепления(0) передается извне.
для i-го шага:
1. считывается i-й блок данных
2. блок зацепления(1) <- i-й блок данных
3. i-й блок подается на дешифратор ГОСТ 28147
4. выход шифратора побитово складывается с блоком зацепления(0)
5. i-й блок расшированных данных <-результат сложения
6. блок зацепления(0)<-блок зацепления(1)

примерно так :)
17.12.2004 14:00:02max
Еще один вопрос про CBC - не могу получить IV:
::CryptGetKeyParam(hKey, KP_IV, pIV, &nLen, 0) возвращает случайный вектор.
Если поменять провайдер и алгоритм на MS AES, то код работает.
17.12.2004 14:47:31Bor1
P_IV работает в этой функции для сессионного ключа (параметр CALG_G28147). Иначе генерировать вектор следует функцией CPGenRandom().
17.12.2004 17:02:07max
Мне не надо генерировать случайные числа, мне
просто надо получить IV:)
Приведенный код должен возвращать IV = {0, 1, 2, 3, 4, 5, 6, 7},
а возвращает мусор:

HCRYPTPROV hProv;
//::CryptAcquireContext(&hProv, NULL, NULL, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT);
::CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);

HCRYPTKEY hKey;
//::CryptGenKey(hProv, CALG_G28147, 0, &hKey);
::CryptGenKey(hProv, CALG_DES, 0, &hKey);

DWORD mode = CRYPT_MODE_CBC;
::CryptSetKeyParam(hKey, KP_MODE, (PBYTE)&mode, 0);

BYTE iv[8] = {0, 1, 2, 3, 4, 5, 6, 7};
ULONG len = 8;
::CryptSetKeyParam(hKey, KP_IV, iv, 0);

char buf[16] = {0};
len = 8;
::CryptEncrypt(hKey, NULL, TRUE, 0, (PBYTE)buf, &len, 16);

len = 8;
::CryptGetKeyParam(hKey, KP_IV, iv, &len, 0);

17.12.2004 17:37:59Василий
Разумеется, так и было задумано.
Значение инитвектора меняется при каждом использовании ключа.
Поэтому, перед зашифрованием и перед расшифрованием нужно устанавливать IV.
Или: перед зашифрованием получать IV (GetKeyParam), сохранять его, а перед расшифрованием устанавливать.
17.12.2004 19:18:15max
OK, т.е. CryptGetKeyParam возвращает не IV, а _текущий_ IV - но ведь это не совпадает с поведением провайдеров от MS?