| ||||
| ||||
Насколько я понимаю, для этого нужно два сертификата: сертификат отправителя (= private key) и сертификат получателя (= public key). То есть, ключ получателя импортируется на ключе отправителя, а затем используется для экспорта сессионного ключа. Но на принимающей стороне нам известен только сертификат получателя, использованный для экспорта (информация о нем лежит в PKCS7 RecipientInfo), однако ничего неизвестно о сертификате отправителя! Как же быть? Кроме того, в CAPICOM в объект EnvelopeData передается только сертификат получателя, откуда же Ваш код (в cpadvai.dll) берет ключ отправителя? Прав ли я, что Вы просто используете CryptGetUserKey для получения ключа _по умолчанию_ для текущего пользователя, а если такового нет – он генерируется на лету? Не кажется ли Вам, что такое неконтролируемое поведение немного некорректно? (Я бы, к примеру, предпочел, чтобы приложение _спросило_ меня какой именно ключ использовать для обмена.) Спасибо. | ||||
Ответы: | ||||
| ||||
Прошу прощения за этот пинг, но все-таки хотелось бы получить ответ на вопрос... | ||||
| ||||
Используется эфемеральный алгоритм DH - эфемерный ключ отправителя лежит в сообщении, и cpadvai здесь не причем. Почитайте повнимательнее PKCS7. | ||||
| ||||
Из описания к СКЗИ CryptoPro CSP 2.0 (csp_2_0.chm): Обычно для согласования (экспорта/импорта) сессионного ключа применяют алгоритм Диффи-Хеллмана. В этом случае ключ парной связи (ключ экспорта/импорта сессионного ключа) порождается операцией импорта открытого ключа получателя (отправителя) на ключевой паре отправителя (получателя). CPExportKey: Для экспорта сессионного ключа следует выполнить следующие шаги: Импорт блоба открытого ключа получателя на своей ключевой паре; Экспорт сессионого ключа на ключе парной связи: ... CPGetUserKey(hProv, AT_KEYEXCHANGE, &hUserKey); ... CPGenKey(hProv, CALG_G28147, CRYPT_EXPORTABLE, &hSessionKey); ... CPImportKey(hProv, pbRecipentPublicKey, cbRecipentPublicKey, hUserKey, 0, &hExchKey); CPExportKey(hProv, hSessionKey, hExchKey, SIMPLEBLOB, 0, pbSessionKeyForRecipient, &cbSessionKeyForRecipient); ... CPImportKey: Для импорта сессионного ключа следует выполнить следующие шаги: Импорт блоба открытого ключа отправителя на своей ключевой паре; Импорт сессионого ключа на ключе парной связи: ... CPGetUserKey(hProv, AT_KEYEXCHANGE, &hUserKey); ... CPImportKey(hProv, pbSenderPublicKey, cbSenderPublicKey, hUserKey, 0, &hExchKey); CPImportKey(hProv, pbSessionKeyFromSender, &cbSessionKeyFromSender, hExchKey, 0, &hSessionKey); ... | ||||
| ||||
Собственно смущает фраза "импорт блоба открытого ключа отправителя на своей ключевой паре" - как видно эфимерный ключ здесь не причем(?), ведь здесь явно импортится ключ отправителя. Поправьте меня, plz, если я чего-то не понимаю (а судя по всему это так :) | ||||
| ||||
Кроме того, для получения ключа обмена используется вызов CPGetUserKey(hProv, AT_KEYEXCHANGE, &hUserKey) - какой контейнер используется в данном случае? Вспомним еще разок: CAPICOM не позволяет выбрать сертификат/ключ _отправителя_, могу лишь предположить, что в cpadvai.dll (а эта DLL здесь именно что причем, ведь код собирающий PKCS7 EnvelopedData на ГОСТ’е находится именно в ней) используется дефолтный контейнер текущего пользователя (лень мне отлаживаться, чтобы установить это точно). | ||||
| ||||
Тьфу, не cpadvai, конечно, а cpcrypt. | ||||
| ||||
Если используете CryptoAPI - можно экспортировать как на эфемеральном, так и на реальном ключе Диффи-Хеллмана. В последнем случае ключ DH получается из своего закрытого и чужого открытого ключа. Если используете CAPICOM - экспортировать получится только на эфемеральном ключе DH. | ||||
| ||||
Угу, начинаю понимать. В таком случае меня интересует именно случай эфемерного ключа DH. Не могли бы Вы указать на пример кода, в котором сессионный ключ выгружается подобным образом? (в примере из sample2_0.zip я нашел только случай реального ключа), меня _особенно_ интересует ручное создание структуры RecipientInfo. P.S.: А с точки зрения криптостойкости, есть ли разница между двумя этими алгоритмами? | ||||
| ||||
> Прав ли я, что Вы просто используете CryptGetUserKey для получения ключа _по умолчанию_ для текущего пользователя, а если такового нет – он генерируется на лету? Нет. Эфемерный ключ отправителя передаётся вместе с зашифрованным сессионным ключем в поле RecipientInfo.EncryptedKey. Подробности смотрите в http://www.ietf.org/internet-drafts/draft-ietf-smime-gost-02.txt | ||||
| ||||
Это понятно. Я говорил про _экспорт_ сессионного ключа. В любом случае (что эфемерный, что реальный ключ) требуется открытый ключ получателя и _секретный ключ отправителя_. С получателем все ясно, в CAPICOM передается сертификат получателя, а вот с ключом отправителя не все ясно: CAPICOM не позволяет выбрать сертификат/ключ отправителя, собственно отсюда и мой вопрос. | ||||
| ||||
2 xyz: PKCS7 здесь абсолютно ни при чем. Максимум, что можно упомянуть, это PKCS3, но там информации минимум (про алгоритм с эфемерным ключом я там не нашел ничего) | ||||
| ||||
> Я говорил про _экспорт_ сессионного ключа. В любом случае (что эфемерный, что реальный ключ) требуется открытый ключ получателя и _секретный ключ отправителя_. Как уже было сказано, схема Fixed DH не поддерживается. То есть, всегда используется эфемеральный (то есть, временный, уникальный для сообщения) ключ отправителя. Никакого контейнера по умолчанию не используется. | ||||