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

Уведомление

Icon
Error

2 Страницы12>
Опции
К последнему сообщению К первому непрочитанному
Offline Dima_Sun  
#1 Оставлено : 16 марта 2009 г. 19:11:24(UTC)
Dima_Sun

Статус: Активный участник

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

Стоит задача шифрования блока данных, сохранение зашифрованных данных (вместе с сессионным ключом) и последующая дешифрация. В качестве основы использован пример RSACert из Windows SDK. Вкратце там делается след. образом:
1. CertFindCertificateInStore() -- Находим нужный сертификат
2. CryptAcquireContext() -- Получение контекста контейнера
3. CryptImportPublicKeyInfo(hRSAKey) -- Получение открытого ключа из сертификата
4. CryptGenKey(hSessionKey) -- Генерация сессионного ключа
5. CryptExportKey(hSessionKey, hRSAKey, .... ) -- Экспорт сессионного ключа в бинарный блок
6. Шифрация сообщения и запись в файл.

С сертификатами, выписанными с использование криптопровайдера от MS - все ок. При попытке использования сертификата КроптоПро получаю ошибку NTE_BAD_KEY_STATE на 5 шаге. При этом для сертификатов от MS по-прежнему работает. Похоже что с КриптоПрошными сертификатами так нельзя. А как можно? Просмотрел массу примеров из вашего SDK. Там есть несколько примеров, в которых встречается CryptExportKey, но во всех из них используются 2 сертификата (отправитель\получатель). В моем же случае - один. Два сертификата в случае с КриптоПро это неизбежность или есть пути?

И заодно... в примере от MS для получения открытого ключа используется CryptImportPublicKeyInfo, а во всех ваших примерах - CryptGetUserKey. Я так понимаю это синонимы. А в чем их нюансы? Я так понимаю CryptImportPublicKeyInfo возвращает открытый ключ для сертификата, контекст которого мы в нее передаем. А CryptGetUserKey ищет соответствующий по криптопровайдеру (первый аргумент) и имени пользователя. Т.е. чтобы CryptGetUserKey что-то вернула нужно иметь сертификат с именем совпадающим с именем пользователя. Так?



Offline Kirill Sobolev  
#2 Оставлено : 16 марта 2009 г. 19:24:51(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,731
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 175 раз в 167 постах
Цитата:
Там есть несколько примеров, в которых встречается CryptExportKey, но во всех из них используются 2 сертификата (отправитель\получатель). В моем же случае - один. Два сертификата в случае с КриптоПро это неизбежность или есть пути?

Это неизбежность схемы Diffie-Helmana. В том случае, если Вы не хотите использовать сертификат отправителя, Вы можете использовать эфемеральную пару (CryptGenKey(..,CALG_DH_EPHEM, ..)).
Цитата:
в примере от MS для получения открытого ключа используется CryptImportPublicKeyInfo, а во всех ваших примерах - CryptGetUserKey. Я так понимаю это синонимы.
Нет. CryptImportPublicKeyInfo работает именно так, как Вы описали, а CryptGetUserKey получает открытый ключ (вернее ключевую пару) из существующего контейнера с секретным ключем, сертификат к этому отношения не имеет.
Техническую поддержку оказываем тут
Наша база знаний
Offline Dima_Sun  
#3 Оставлено : 16 марта 2009 г. 19:57:08(UTC)
Dima_Sun

Статус: Активный участник

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

В ваших примерах упоминания такой константы (CALG_DH_EPHEM) не обнаружилось и на форуме тоже.
Насколько я понял надо сделать как у вас в примерах, только вместо открытого ключа из сертификата отправителя использовать ключ сгенерированный при помощи CryptGenKey(..,CALG_DH_EPHEM, ..)

Offline Kirill Sobolev  
#4 Оставлено : 16 марта 2009 г. 20:25:37(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,731
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 175 раз в 167 постах
У нас форум переезжал :) Вот тут эта тема обсуждается http://www.cryptopro.ru/...topro/forum/view.asp?q=4
Да, для примера используется несколько упрощенная ситуация, поэтому и эфемеральные ключи не создаются.
Техническую поддержку оказываем тут
Наша база знаний
Offline Роман кислухин  
#5 Оставлено : 15 августа 2013 г. 23:46:05(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Добрый день

Также интересует данный вопрос. Нужно шифрование/дешифрование блока данных.

Попробовал использовать CryptGenKey(..,CALG_DH_EPHEM,..), но всегда получаю ошибку:

An internal error occurred.
(0x80090020)

Последовательность следующая:

1. Получаем хэндл криптопровайдера:
prov = CryptAcquireContext(null, null, PROV_GOST_2001_DH, 0);
или даже
prov = CryptAcquireContext("MyContainer", null, PROV_GOST_2001_DH, CRYPT_NEWKEYSET);

2. Пытаемся сгенерировать эфемеральную пару:
CryptGenKey(hProv, CALG_DH_EPHEM, 512 << 16 | CRYPT_EXPORTABLE);
или
CryptGenKey(hProv, CALG_DH_EPHEM, 0);

Неизбежно получаем (0x80090020)

Что я делаю не так?

Можно ли схематичный пример, как сделать шифрование на публичном ключе (имея сертификат) и дешифрование на секретном (имея контейнер с секретным ключем)?


Update
Так, похоже эфемеральную пару сгенерировал, используя константу CALG_DH_EL_EPHEM.
Как теперь правильно выполнить шифрование и дешифрование? Неправильно делать научился, но результат дешифрования не совпадает с исходными данными (исходник чуть позже будет).

Отредактировано пользователем 16 августа 2013 г. 0:33:48(UTC)  | Причина: Не указана

Offline Андрей Писарев  
#6 Оставлено : 16 августа 2013 г. 0:00:25(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 9,553
Мужчина
Российская Федерация

Сказал «Спасибо»: 343 раз
Поблагодарили: 1371 раз в 1059 постах
Предлагаю открыть руководство разработчика на сайте, там есть пример.
Техническую поддержку оказываем тут
Наша база знаний
Offline Роман кислухин  
#7 Оставлено : 16 августа 2013 г. 0:37:24(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Автор: Андрей * Перейти к цитате
Предлагаю открыть руководство разработчика на сайте, там есть пример.


Где конкретно? Нашел только описание функций CryptEncrypt/CryptDecrypt, но это и в MSDN есть.
Offline Юрий  
#8 Оставлено : 16 августа 2013 г. 5:38:08(UTC)
Юрий

Статус: Активный участник

Группы: Участники
Зарегистрирован: 22.01.2008(UTC)
Сообщений: 667
Мужчина
Российская Федерация
Откуда: Йошкар-Ола

Сказал «Спасибо»: 2 раз
Поблагодарили: 93 раз в 67 постах
Автор: Роман кислухин Перейти к цитате
Автор: Андрей * Перейти к цитате
Предлагаю открыть руководство разработчика на сайте, там есть пример.


Где конкретно? Нашел только описание функций CryptEncrypt/CryptDecrypt, но это и в MSDN есть.

Видимо вопрос уже настолько частый, что его занесли прямо в FAQ: http://www.cryptopro.ru/faq/eksport-sessionnogo-klyucha
Кстати и правильно сделали что занесли.
С уважением,
Юрий Строжевский
Offline Андрей Писарев  
#9 Оставлено : 16 августа 2013 г. 8:25:55(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 9,553
Мужчина
Российская Федерация

Сказал «Спасибо»: 343 раз
Поблагодарили: 1371 раз в 1059 постах
Автор: Юрий Перейти к цитате
Автор: Роман кислухин Перейти к цитате
Автор: Андрей * Перейти к цитате
Предлагаю открыть руководство разработчика на сайте, там есть пример.


Где конкретно? Нашел только описание функций CryptEncrypt/CryptDecrypt, но это и в MSDN есть.

Видимо вопрос уже настолько частый, что его занесли прямо в FAQ: http://www.cryptopro.ru/faq/eksport-sessionnogo-klyucha
Кстати и правильно сделали что занесли.


И взято было из старого форума
Цитата:
Ответ:
05.01.2001 11:20:55


Техническую поддержку оказываем тут
Наша база знаний
Offline Роман кислухин  
#10 Оставлено : 16 августа 2013 г. 11:18:38(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Автор: Андрей * Перейти к цитате
Автор: Юрий Перейти к цитате
Автор: Роман кислухин Перейти к цитате
Автор: Андрей * Перейти к цитате
Предлагаю открыть руководство разработчика на сайте, там есть пример.


Где конкретно? Нашел только описание функций CryptEncrypt/CryptDecrypt, но это и в MSDN есть.

Видимо вопрос уже настолько частый, что его занесли прямо в FAQ: http://www.cryptopro.ru/faq/eksport-sessionnogo-klyucha
Кстати и правильно сделали что занесли.


И взято было из старого форума
Цитата:
Ответ:
05.01.2001 11:20:55




Спасибо.

Страницу старого форума я и так поиском нашел, оттуда и была взята константа, которая не работает. И пример написан для двух ключевых пар, а примера с эфемерным ключем нет. Да и само описание не очень понятное (если честно, совсем непонятное для случая с эфемерными ключами), причесать бы его.
Offline Роман кислухин  
#11 Оставлено : 16 августа 2013 г. 12:52:08(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Итак. Получен кусок неработающего кода. Приведу его как есть на Java, чтобы не ошибиться при транслировании на Си. Он в принципе понятен.

Шифрование проходит без проблем:
Код:

  public static CryptData cryptData(PCCERT_CONTEXT cert, byte[] data) throws CryptoException {
    final KeyContext userKey = SignUtils.getUserKey(cert);
    if (userKey == null)
      throw new CryptoException("User key not found");
    final Pointer sessKey = Advapi.cryptGenKey(userKey.getProvHandle(), Wincrypt.CALG_G28147, Wincrypt.CRYPT_EXPORTABLE);
    try {
      final byte[] ecnryptedData = Advapi.cryptEncrypt(sessKey, null, true, data);
      final byte[] iv = new byte[8];
      final byte[] sv = new byte[8];
      final byte[] sessKeyData = exportSessionKey(userKey, sessKey, iv, sv);
      return new CryptData(ecnryptedData, sessKeyData, iv, sv);
    } finally {
      userKey.free();
    }
  }

  private static byte[] exportSessionKey(KeyContext userKey, Pointer sessionKey, /* out */ byte[] iv, /* out */ byte[] sv) throws CryptoException {
    final Pointer hProv = userKey.getProvHandle();
    // получаем вектор инициализации
    final byte[] ivData = cryptGetKeyParam(sessionKey, KP_IV);
    // копируем вектор в out - переменную
    System.arraycopy(ivData, 0, iv, 0, 8);

    // генерируем ефемерную пару
    final Pointer ephemKey = Advapi.cryptGenKey(hProv, CALG_DH_EL_EPHEM, CRYPT_EXPORTABLE);

    // Генерируем в 2 шага ключ согласования agreeKey. Для этого импортируем наш публичный ключ, используя эфемерную пару.
    // 1. Экспортируем наш публичный ключ
    final byte[] pubKeyData = cryptExportKey(userKey.getKeyHandle(), null, PUBLICKEYBLOB, 0);
    // 2. Импортируем при помощи эфемерной пары
    final Pointer agreeKey = Advapi.cryptImportKey(hProv, pubKeyData, ephemKey, 0);

    // получаем вектор инициализации
    final byte[] svData = cryptGetKeyParam(agreeKey, KP_IV);
    // копируем вектор в out - переменную
    System.arraycopy(svData, 0, sv, 0, 8);

    // Экспортируем симметричный ключ шифрования с использованием ключа согласования
    final byte[] sessKeyData = cryptExportKey(sessionKey, agreeKey, SIMPLEBLOB, 0);

    return sessKeyData;
  }

В результате получаем зашифрованный симметричный сессионный ключ и два вектора инициализации.
А вот с расшифровкой проблемы:

Код:

  public static byte[] decryptData(PCCERT_CONTEXT cert, CryptData cdata) throws CryptoException {
    final KeyContext userKey = SignUtils.getUserKey(cert);
    if (userKey == null)
      throw new CryptoException("User key not found");
    final Pointer sessKey = importSessionKey(userKey, cdata);
    try {
      final byte[] data = Advapi.cryptDecrypt(sessKey, null, true, 0, cdata.cryptedData);
      return data;
    } finally {
      userKey.free();
    }
  }

  private static Pointer importSessionKey(KeyContext userKey, CryptData cdata) throws CryptoException {
    final Pointer hProv = userKey.getProvHandle();
    // генерируем ефемерную пару
    final Pointer ephemKey = Advapi.cryptGenKey(hProv, CALG_DH_EL_EPHEM, CRYPT_EXPORTABLE);

    // Генерируем в 2 шага ключ согласования agreeKey. Для этого импортируем эфемерный открытый ключ, используя нашу ключевую пару.
    // 1. Экспортируем эфемерный публичный ключ
    final byte[] ephemPubKeyData = cryptExportKey(ephemKey, null, PUBLICKEYBLOB, 0);
    // 2. Импортируем при помощи ключевой пары
    final Pointer agreeKey = Advapi.cryptImportKey(hProv, ephemPubKeyData, userKey.getKeyHandle(), 0);

    // устанавливаем вектор инициализации
    cryptSetKeyParam(agreeKey, KP_IV, cdata.sv, 0);

    // Импортируем симметричный ключ шифрования с использованием ключа согласования
    final Pointer sessKey = cryptImportKey(hProv, cdata.ecnryptedKey, agreeKey, 0);
    if (sessKey == null) 
      throw CryptoUtil.raiseCryptoError("cryptImportKey", getLastError()); // ОШИБКА ЗДЕСЬ. Bad data (0x80090005)

    // Не забываем вектор инициализации
    final byte[] ivData = cdata.iv;
    cryptSetKeyParam(sessKey, KP_IV, ivData, 0);

    return sessKey;
  }

Возникает ошибка на этапе импорта сессионного ключа - Bad data (0x80090005).

Что пропустил? Подвох в эфемерном ключе? Надо передавать его значение вместе со всеми данными? Или еще где ошибся?

отступы почему-то пропали :(

Отредактировано пользователем 16 августа 2013 г. 12:58:47(UTC)  | Причина: Не указана

Offline Роман кислухин  
#12 Оставлено : 16 августа 2013 г. 14:01:16(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Так, с двумя ключевыми парами пример заработал. Значит дело в эфемерном ключе. Попробую CRYPT_PREGEN - где-то видел в примерах.
Offline Максим Коллегин  
#13 Оставлено : 16 августа 2013 г. 14:04:01(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 5,972
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 17 раз
Поблагодарили: 586 раз в 527 постах
cryptGenKey(hProv, CALG_DH_EL_EPHEM, CRYPT_EXPORTABLE); при экспорте и импорте - это что-то странное. Передавайте открытый ключ эферного ключа на сторону расшифрования.
Знания в базе знаний, поддержка в техподдержке
Offline Роман кислухин  
#14 Оставлено : 16 августа 2013 г. 14:25:05(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Автор: maxdm Перейти к цитате
cryptGenKey(hProv, CALG_DH_EL_EPHEM, CRYPT_EXPORTABLE); при экспорте и импорте - это что-то странное. Передавайте открытый ключ эферного ключа на сторону расшифрования.


Согласен. Сейчас попробую целиком его экспортнуть.
Offline Роман кислухин  
#15 Оставлено : 16 августа 2013 г. 14:33:51(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Не помогло. Что-то еще не так.

делаю так:
Код:

    // экспортируем эфемерный ключ. Он нам понадобится для расшифрования.
    cdata.pubKeyData = cryptExportKey(ephemKey, null, PUBLICKEYBLOB, 0);

    // получаем вектор инициализации
    cdata.sv = cryptGetKeyParam(agreeKey, KP_IV);

    // Экспортируем симметричный ключ шифрования с использованием ключа согласования
    cdata.ecnryptedKey = cryptExportKey(sessionKey, agreeKey, SIMPLEBLOB, 0);


потом
Код:

    // Импортируем при помощи ключевой пары
    final Pointer agreeKey = cryptImportKey(hProv, cdata.pubKeyData, userKey.getKeyHandle(), 0);

    // устанавливаем вектор инициализации
    cryptSetKeyParam(agreeKey, KP_IV, cdata.sv, 0);

    // Импортируем симметричный ключ шифрования с использованием ключа согласования
    final Pointer sessKey = cryptImportKey(hProv, cdata.ecnryptedKey, agreeKey, 0);


И все равно Bad data.
Offline Максим Коллегин  
#16 Оставлено : 16 августа 2013 г. 14:53:46(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 5,972
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 17 раз
Поблагодарили: 586 раз в 527 постах
хм, вектор инициализации нужно ставить сессионному ключу. Вы наши примеры из SDK смотрели? Зачем гадать?
Знания в базе знаний, поддержка в техподдержке
Offline Роман кислухин  
#17 Оставлено : 16 августа 2013 г. 14:59:56(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Автор: maxdm Перейти к цитате
хм, вектор инициализации нужно ставить сессионному ключу. Вы наши примеры из SDK смотрели? Зачем гадать?


Ему я тоже ставлю, но до этого не доходит.
Самое интересное, что этот же код работает при наличии двух ключевых пар. А вот с эфемерной - не работает.
Если убрать установку вектора инициализации для ключа согласования, все равно выдает Bad data.

p.s. не стало работать :( разбираюсь. Судя по всему, причина в неаккуратном использовании хэндлов на провайдер. Сколько их должно быть для всех операций шифрования/дешифрования?

Отредактировано пользователем 16 августа 2013 г. 15:08:38(UTC)  | Причина: Не указана

Offline Максим Коллегин  
#18 Оставлено : 16 августа 2013 г. 15:11:02(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 5,972
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 17 раз
Поблагодарили: 586 раз в 527 постах
Мда.
При шифровании вообще ерунда какая-то. Зачем вы импортируете открытый эферный ключ в закрытый. Закрытый ключ отправителя в этой схеме вообще не нужен.
Знания в базе знаний, поддержка в техподдержке
Offline Максим Коллегин  
#19 Оставлено : 16 августа 2013 г. 15:11:25(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 5,972
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 17 раз
Поблагодарили: 586 раз в 527 постах
Еще раз повторяю - посмотрите примеры.
Знания в базе знаний, поддержка в техподдержке
Offline Роман кислухин  
#20 Оставлено : 16 августа 2013 г. 15:19:54(UTC)
Роман кислухин

Статус: Активный участник

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

Сказал «Спасибо»: 3 раз
Автор: maxdm Перейти к цитате
Еще раз повторяю - посмотрите примеры.


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

смотрю сюда:
http://cpdn.cryptopro.ru...ngSessionKeyExample.html
в этой схеме используются оба ключа, и импорт публичного ключа получателя делается с ключевой парой отправителя. С эфемерной не так?

Отредактировано пользователем 16 августа 2013 г. 15:29:49(UTC)  | Причина: Не указана

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