Работа с RuToken средствами CryptoAPI

Добрый день! Есть задача лицензирования ПО. Суть в следующем: есть выпускающая сторона, и есть клиент. Есть 2 пары ключей RSA: 1-я — «собственный» ключ, 2-я — «экспортный»; сгенерированный файл лицензии сначала шифруется на выпускающей стороне 1-м закрытым ключом, а затем — 2-м открытым. 1-й открытый ключ хранится в модуле лицензирования (поэтому он «собственный»), 2-й записывается на токен. Соответственно, у клиента надо сначала расшифровать лицензию 2-м закрытым, а затем — 1-м открытым (который хранится в модуле). Такова постановка задачи, менять её не надо.
Вопрос: как средствами CryptoAPI расшифровать лицензию закрытым ключом неявно (например, сделать это средствами самого токена), т.е. чтобы его нельзя было извлечь и, соответственно, использовать в своих целях? Интересует подробный алгоритм как шифрования и записи данных на токен, так и обратного процесса (просто я пока слабо представляю себе эту картину даже в общих деталях).

Т.к. я новичок в крипции вообще и в вопросах использования RuToken — в частности, просьба разворачивать свой ответ, дабы было понятно не только профессионалам ☺ И просьба простить меня за возможные некорректные формулировки в вопросах.
Заранее спасибо!

Re: Работа с RuToken средствами CryptoAPI

Постановку задачи можно немного облегчить, интересует именно вопрос с «собственным» ключом — как реализовать этот вариант с модулем RuToken и какой лучше использовать?
Я сделал тестовый пример, реализующий следующие действия:
а) на выпускающей стороне:
— открываю контейнер посредством CryptAcquireContext (или создаю новый, генерирую асимметричный ключ с помощью CryptGenKey(AT_KEYEXCHANGE,CRYPT_ARCHIVABLE) и экспортирую PRIVATEKEYBLOB);
— получаю дескриптор ключа посредством CryptGetUserKey(AT_KEYEXCHANGE);
— генерирую сессионный ключ с помощью CryptGenKey(CALG_RC4) и экспортирую его посредством CryptExportKey(SIMPLEBLOB) совместно с зашифрованными им через CryptEncrypt данными, сохраняя это в одно сообщение;
— разрушаю/закрываю ключи/хранилища.
б) на принимающей стороне:
— открываю контейнер посредством CryptAcquireContext (или создаю новый, импортировав экспортированный на стороне а) ключ посредством CryptImportKey;
— получаю дескриптор ключа посредством CryptGetUserKey(AT_KEYEXCHANGE);
— открываю сообщение, импортируя оттуда ключ через CryptImportKey и расшифровывая им остаток сообщения;
— разрушаю/закрываю ключи/хранилища.

Тонким местом здесь является экспорт ключевой пары в источнике и импорт оной в приёмнике. Разумеется, конечному пользователю эта информация не должна быть доступна, дабы он не завладел закрытым ключом, для этой цели как раз и служит токен. Сохранится ли эта последовательность в случае работы с токеном, или надо будет внести какие-то серьёзные изменения? Возможно, также будут какие-то тонкости, которые мне неизвестны.

Re: Работа с RuToken средствами CryptoAPI

Да, вы правильно нашли тонкое место :)
Если вы создаете закрытый ключ на токене - то вы не сможете его извлекать.
Каждый раз нужно будет расшифровывать что-то только с  использованием токена.

К первому вашему посту, есть вопрос:

apixosoft пишет:

сгенерированный файл лицензии сначала шифруется на выпускающей стороне 1-м закрытым ключом, а затем — 2-м открытым

Что значит шифруется сначала открытым, а потом закрытым?

В схеме RSA возможно шифрование только на открытом ключе, а расшифрование на закрытом.
Вы ничего не путаете?

Re: Работа с RuToken средствами CryptoAPI

Кирилл Мещеряков пишет:

Да, вы правильно нашли тонкое место :)
Если вы создаете закрытый ключ на токене - то вы не сможете его извлекать.
Каждый раз нужно будет расшифровывать что-то только с  использованием токена.

Вы, верно, не очень внимательно читали тему :) Как раз-таки этого я и добиваюсь, чтобы расшифровывать можно было только с помощью токена. То есть та же самая последовательность инструкций (за исключением того, что я создаю не локально ключ, а на токене, и ничего не экспортирую/импортирую) будет работать и при использовании токена? (0)

Кирилл Мещеряков пишет:

К первому вашему посту, есть вопрос:
Что значит шифруется сначала открытым, а потом закрытым?
В схеме RSA возможно шифрование только на открытом ключе, а расшифрование на закрытом.
Вы ничего не путаете?

Кажется, немного попутал, да ☺ Вернее, не уточнил — имелась в виду цифровая подпись, ведь она делается закрытым ключом в источнике, верно? (1)

Re: Работа с RuToken средствами CryptoAPI

И ещё пара вопросов:
• можно ли сгенерировать ключ на токене, а потом экспортировать его (2а)? Но только однажды, сразу после создания, как CRYPT_ARCHIVABLE. Либо, в противном случае, сгенерировать его локально и записать на токен (2б), потому что локально нужно иметь всю ключевую пару.
• надо ли для генерации ключа получать контекст с флагом CRYPT_MACHINE_KEYSET, или ключи должны быть пользовательские, т.е. использовать параметры по умолчанию? (3)

Re: Работа с RuToken средствами CryptoAPI

Тема всё ещё актуальна.

Re: Работа с RuToken средствами CryptoAPI

2а - можно, например в PFX (но если устройство не Рутокен ЭЦП, в Рутокен ЭЦП экспорт закрытого ключа невозможен)
2б - тоже можно (импорт PFX)
3. в Актив Рутокен CSP этот флаг вообще не поддерживается