| ||||
| ||||
Здравствуйте. Не подскажите, как в 3.0 (используем 3293) сгенерить симметричный ключ, чтобы он потом импортировался у клиентов с 1.1.129.1? Используем, естественно, ГОСТ-94. В прошлый раз (когда добивался совместимости 2.0 с 1.1) проблема решалась вызовом CryptSetKeyParam с KP_ALGID - CALG_PRO_EXPORT. (подробнее здесь, с 4-го поста: http://www.cryptopro.ru/cryptopro/forum/view.asp?q=1659) Спасибо | ||||
Ответы: | ||||
| ||||
А сейчас какая ситуация - контейнер с ключом ГОСТ 94 сделан на 3.0 или нет? И второе 3.0-3.0 3.0-2.0 2.0-3.0 работает? | ||||
| ||||
Контейнер с секретным ключом сделан в 1.1. Связки 3.0-3.0 3.0-2.0 2.0-3.0 работают. Оказалось, не работает и связка 2.0(сервер) - 1.1 (клиент), где симметричные ключи создаются только на сервере (а у клиентов только импортируются). Раньше нужна была только связка 1.1 (сервер) - 2.0 (клиент), и там импорт симметричного ключа (создаваемого всегда в 1.1) у клиента 2.0 заработал, когда я стал делать CryptSetKeyParam(..KP_ALGID.. CALG_PRO_EXPORT..) комбинированному ключу, на котором импортировал потом симметричный. Сейчас получаю ошибку "Invalid type specified (8009000A)" в CryptImportKey, если, например: - беру серверный секретный ключ, созданный в 1.1, - генерирую в 2.0 симметричный ключ (и зашифровываю его серверной парой) - дальше в 1.1 пытаюсь перешифровать этот симметричный ключ на публичном ключе клиента, созданном в 1.1 - и при импорте симметричного получаю ошибку. Может, какой-то параметр провайдера нужно подкрутить, чтобы симметричный ключ, создаваемый в 2.0, стал совместим/успешно импортировался в 1.1? | ||||
| ||||
Идей по решению проблемы, описанной в последнем сообщении, не возникло? | ||||
| ||||
Честно говоря, не очень понятно: "- беру серверный секретный ключ, созданный в 1.1, - генерирую в 2.0 симметричный ключ (и зашифровываю его серверной парой) - дальше в 1.1 пытаюсь перешифровать этот симметричный ключ на публичном ключе клиента, созданном в 1.1 - и при импорте симметричного получаю ошибку" Можно чуть подробнее - какие ключи (AT_KEYEXCHANGE, Диффи-Хеллмана, сессионные) и какие функции вызываются? | ||||
| ||||
1) Генерирую ключи на машине с КриптоПро 1.1 (1.1.129.1): CryptAcquireContext(..., 'Crypto-Pro Cryptographic Service Provider', PROV_GOST_DH, ...); // создание контейнера ГОСТ-94 CryptGenKey(..., AT_KEYEXCHANGE, ...); // генерация секретного и публичного ключей (в реестре) CryptExportPublicKeyInfo(..., AT_KEYEXCHANGE, ...); // экспорт публичного ключа в формате публичного ключа сертификата в файл (в этом формате публичный ключ храню и передаю, так он совпадает с тем, что видно при просмотре сертификата стандартными средствами) CryptExportKey(...PUBLICKEYBLOB...); // обычный экспорт публичного ключа (в принципе, не нужен, далее не используется, вызов остался исторически) 2) Переношу фрагмент реестра с контейнером секретнго и публичного ключей (HKEY_LOCAL_MACHINE\SOFTWARE\Crypto Pro\Settings\USERS\<SID_пользователя>\Keys\<контейнер>) на машину с КриптоПро 2.0 (Build 2091) и на ней генерирую симметричный ключ: CryptAcquireContext(..., 'Crypto-Pro Cryptographic Service Provider', PROV_GOST_DH, ...); // доступ к контейнеру ГОСТ-94 [пробуя с 3.0 вместо 2.0, естественно, использовал 'Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider', PROV_GOST_94_DH] CryptGeKey(... CALG_G28147, CRYPT_EXPORTABLE, ...); // генерирую симметричный ключ CryptGetKeyParam(... KP_IV ...); // читаю инициализационный вектор для симметричного ключа, чтобы посмотреть его длину CryptSetKeyParam(... KP_IV, <буфер с нулями для инициализационного вектора>, ...); // задаю инициализационный вектор из нулей CryptGetUserKey(..AT_KEYEXCHANGE...&selfkey); // получаю дескриптор секретного и публичного ключей контейнера CryptImportPublicKeyInfo(..X509_ASN_ENCODING or PKCS_7_ASN_ENCODING..); // импортирую публичный ключ из файла (в данном случае - это тот же публичный ключ, что и в контейнере) CryptExportKey(... PUBLICKEYBLOB...&selfpubstr); // экспортирую только что проимпортированный публичный ключ - в формате, требуемом для формирования совместного ключа CryptImportKey(...selfpubstr...selfkey...); // формирую совместный ключ (в данном случае - из одних и тех же - собственных - ключей) CryptSetKeyParam(...KP_ALGID, CALG_PRO_EXPORT...); // добавлялось для совместимости 1.1 с 2.0, когда на сервере было 1.1, а у некоторых клиентов появилось 2.0 [задание CALG_PRO_EXPORT для совместного ключа у клиентов с 2.0 позволило импортировать у них симметричный ключ, формируемый только на сервере, где тогда было 1.1; сейчас, когда на сервере хотим сделать 2.0, а у некоторых клиентов осталось 1.1 - это не спасает] CryptExportKey(..симметричный ключ, совместный ключ, SIMPLEBLOB); // экспортируем созданный симметричный ключ на совместном, в файл - в таком виде симметричный ключ хранится на сервере (а пользователям раздается перешифрованный на их публичных ключах) 3) Теперь для эксперимента переношу контейнером секретного и публичного ключей обратно на машину с КриптоПро 1.1 и попробую на ней перешифровать симметричный ключ (созданный в 2.0), на публичном ключе одного из клиентов (до которого дело не доходит, ошибка еще на этапе импорта симметричного): CryptAcquireContext(..., 'Crypto-Pro Cryptographic Service Provider', PROV_GOST_DH, ...); // доступ к контейнеру ГОСТ-94 CryptGetUserKey(..AT_KEYEXCHANGE...&selfkey); // получаю дескриптор секретного и публичного ключей контейнера CryptImportPublicKeyInfo(..X509_ASN_ENCODING or PKCS_7_ASN_ENCODING..); // импортирую свой публичный ключ из файла (в данном случае - это тот же публичный ключ, что и в контейнере) CryptExportKey(... PUBLICKEYBLOB...&selfpubstr); // экспортирую только что проимпортированный публичный ключ - в формате, требуемом для формирования совместного ключа CryptImportKey(...selfpubstr...selfkey...); // формирую совместный ключ (в данном случае - из одних и тех же - собственных - ключей) CryptSetKeyParam(...KP_ALGID, CALG_PRO_EXPORT...); // добавлялось для совместимости 1.1 на сервере с 2.0 на клиенте... CryptImportKey(...симметричный ключ...совместный ключ...); // пытаюсь импортировать симметричный ключ из файла Ошибка - Invalid type specified (8009000A) Если этап 3) сделать в 2.0, то все хорошо. Но если полученный перешифрованный на клиентском публичном симметричный ключ отдать клиенту с 1.1 - то у него он не импортируется, с аналогичной ошибкой в CryptImportKey(...симметричный ключ...совместный ключ...). Что не так? P.S. Подозреваю, что либо CryptGeKey в 2.0 создает симм. ключ, несовместимый с 1.1, либо формат симметричного ключа, экспортированного при CALG_PRO_EXPORT, в 2.0 и 1.1 отличаются - в 2.0 какие-то новшества, не понимаемые 1.1. Можно ли их вычистить? (и заодно можно ли по формату экспорта симм. ключа определить, создан ли он в 2.0?) P.P.S. Вы когда-то рекомендовали использовать CALG_SIMPLE_EXPORT, но он, во-первых, не очень безопасен вроде, а во-вторых уже созданные на сервере в 1.1 симметричные ключи - в 2.0 у клиентов понимаются только при задании CALG_PRO_EXPORT. | ||||
| ||||
Можно попросить Вас проверить такую модификацию (на этапах 2 и 3): исключить вызов CryptImportPublicKeyInfo, блоб PUBLICKEYBLOB получать экспортом самого ключа AT_KEYEXCHANGE. | ||||
| ||||
Заменил в 1) использование результата CryptExportPublicKeyInfo на использование результата CryptExportKey, а в 2) и 3) заменил CryptImportPublicKeyInfo на вызов CryptImportKey - не помогло. Также пробовал менять CALG_PRO_EXPORT на CALG_SIMPLE_EXPORT, в том числе вместе с переходом на CryptImportKey - не помогало. Симметричный ключ в 2.0 всегда получается 71 байт, а в 1.1 - 67 байт. Первый имеет структуру: #1#0#0#0#30'f'#0#0<далее 4 байта>#30'f'<остаток данных ключа, в конце 10 постоянные символов> Второй имеет структуру: #1#0#0#0#30'f'#0#0#30'f'<остаток данных ключа той же длины, в конце те же 10 постоянные символов> В общем, визуально отличие на 4 байта с 9-го байта. Пробовал их убрать, чтоб получить 67-байтный ключ - такой ключ не воспринялся с ошибкой при импорте Bad Data (80090005). [такая же ошибка, если использовать CALG_SIMPLE_EXPORT]... | ||||
| ||||
Если использовать CryptImportKey вместо CryptImportPublicKeyInfo (а также задавать CALG_PRO_EXPORT совместному ключу) и при этом при переносе симметричного ключа из 2.0 в 1.1 вручную убирать из него те 4 байта с 9-й позиции (эти байты - это сигнатура #define G28147_MAGIC 0x374a51fd), то симметричный ключ, созданный в 2.0, - воспринимается версией 1.1 А нельзя ли не отказываться от использования CryptImportPublicKeyInfo? А то у меня все ключи клиентов уже в формате CryptImportPublicKeyInfo (так понимаю, в этом формате что-то теряется по сравнению с форматом CryptImportKey) [формат CryptImportPublicKeyInfo был выбран, т.к. такой формат публичного ключа - совпадает с тем, что видно в сертификате у клиента, в поле публичного ключа, а из формата CryptImportKey не умею получать формат CryptImportPublicKeyInfo, не имея секретного ключа). | ||||
| ||||
После консультаций с разработчиками выработаны рекомендации: 1) можно оставить CryptExportPublicKeyInfo/CryptImportPublicKeyInfo 2) блобы типа SIMPLEBLOB не обязаны быть совместимыми между разными версиями CSP, поэтому требуется самостоятельно контролировать версию CSP и перед импортом сессионного ключа из блоба преобразовывать этот блоб в соответствии с особенностями версии CSP. | ||||
| ||||
Для информации. Для совместимости симметричных ключей, созданных в КриптоПро 2.0, 3.0 - с КриптоПро 1.1 у клиента мне пришлось: а) при импорте ключа у клиента с 1.1 удалять в нем сигнатуру 374A51FDh с байта со смещением 8, уменьшая ключ с 71 до 67 байтов; б) исправлять байт версии в публичном ключе со смещением 1 - с 20h (версия 2) на 00h, если следующий (описанный в документации как зарезервированный) байт равен 0 (как оказалось, КриптоПро 2.0 и выше при перешифрации делает симметричные ключи, совместимые с 1.1 только если публичный ключ клиента - от 1.1; а при импорте ключа из формата хранения в сертификате (CryptImportPublicKeyInfo) и экспорте потом в обычный формат (CryptExportKey) - в КриптоПро 2.0 и выше байт версии публичного ключа меняется с 00h на 20h, в результате ключ не считается созданным в 1.1; правда, в следующем байте (т.е. том, что описан в документации как зарезервированный) для ключей от 2.0 и выше помечается 1, а для ключей от 1.1 - нет - поэтому их все же можно вручную отличить и исправить версию). Провел более 200 разных вариантов тестов (вроде таких: ключи сервера созданы в КриптоПро 1.1, симметричные в 2.0, перешифррованы на публичных клиента в 3.0, у клиента 1.1, 2.0 или 3.0) – у меня все работало. | ||||
| ||||
Всё верно - отличие в версии блоба и в наличии MAGIC. | ||||