Header key что это
Перейти к содержимому

Header key что это

  • автор:

Установка сертификата и закрытого ключа

Мы опишем установку сертификата электронной подписи и закрытого ключа для ОС семейства Windows. В процессе настройки нам понадобятся права Администратора (поэтому нам может понадобится сисадмин, если он у вас есть).

Если вы еще не разобрались что такое Электронная подпись, то пожалуйста ознакомьтесь вот с этой инструкцией. Или если еще не получили электронную подпись, обратитесь в Удостоверяющий центр, рекомендуем СКБ-Контур.

Хорошо, предположим у вас уже есть электронная подпись (токен или флешка), но OpenSRO сообщает что ваш сертификат не установлен, такая ситуация может возникнуть, если вы решили настроить ваш второй или третий компьютер (разумеется подпись не «прирастает» только к одному компьютеру и ее можно использовать на нескольких компьютерах). Обычно первоначальная настройка осуществляется с помощью техподдержки Удостоверяющего центра, но допустим это не наш случай, итак поехали.

1. Убедитесь что КриптоПро CSP 4 установлен на вашем компьютере

Для этого зайдите в меню Пуск КРИПТО-ПРО КриптоПро CSP запустите его и убедитесь что версия программы не ниже 4-й.

Если ее там нет, то скачайте, установите и перезапустите браузер.

2. Если у вас токен (Рутокен например)

Прежде чем система сможет с ним работать понадобится установить нужный драйвер.

  • Драйверы Рутокен:https://www.rutoken.ru/support/download/drivers-for-windows/
  • Драйверы eToken:https://www.aladdin-rd.ru/support/downloads/etoken
  • Драйверы JaCarta:https://www.aladdin-rd.ru/support/downloads/jacarta

Алгоритм такой: (1) Скачиваем; (2) Устанавливаем.

Для токена может понадобиться стандартный (заводской) пин-код, здесь есть стандартные пин-коды носителей.

3. Если закрытый ключ в виде файлов

Закрытый ключ может быть в виде 6 файлов: header.key , masks.key , masks2.key , name.key , primary.key , primary2.key

Тут есть тонкость если эти файлы записаны на жесткий диск вашего компьютера, то КриптоПро CSP не сможет их прочитать, поэтому все действия надо производить предварительно записав их на флешку (съемный носитель), причем нужно расположить их в папку первого уровня, например: E:\Andrey\ , если расположить в E:\Andrey\keys\ , то работать не будет.

(Если вы не боитесь командной строки, то съемный носитель можно сэмулировать примерно так: subst x: C:\tmp появится новый диск (X:), в нем будет содержимое папки C:\tmp, он исчезнет после перезагрузки. Такой способ можно использовать если вы планируете установить ключи в реестр)

Нашли файлы, записали на флешку, переходим к следующему шагу.

4. Установка сертификата из закрытого ключа

Теперь нам нужно получить сертификат, сделать это можно следующим образом:

  1. Открываем КриптоПро CSP
  2. Заходим на вкладку Сервис
  3. Нажимаем кнопку Просмотреть сертификаты в контейнере, нажимаем Обзор и здесь (если на предыдущих шагах сделали все правильно) у нас появится наш контейнер. Нажимаем кнопку Далее, появятся сведения о сертификате и тут нажимаем кнопку Установить (программа может задать вопрос проставить ли ссылку на закрытый ключ, ответьте «Да»)
  4. После этого сертификат будет установлен в хранилище и станет возможным подписание документов (при этом, в момент подписания документа, нужно будет чтобы флешка или токен были вставлены в компьютер)

5. Использование электронной подписи без токена или флешки (установка в реестр)

Если скорость и удобство работы для вас стоит чуть выше чем безопасность, то можно установить ваш закрытый ключ в реестр Windows. Для этого нужно сделать несколько простых действий:

  1. Выполните подготовку закрытого ключа, описанную в пунктах (2) или (3)
  2. Далее открываем КриптоПро CSP
  3. Заходим на вкладку Сервис
  4. Нажимаем кнопку Скопировать
  5. С помощью кнопки Обзор выбираем наш ключ
  6. Нажимаем кнопку Далее, потом придумаем какое-нибудь имя, например «Пупкин, ООО Ромашка» и нажимаем кнопку Готово
  7. Появится окно, в котором будет предложено выбрать носитель, выбираем Реестр, жмем Ок
  8. Система попросит Установить пароль для контейнера, придумываем пароль, жмем Ок

Чтобы для сертификата проставить ссылку на этот закрытый ключ выполните действия из пункта (4).

Важное замечание: портал OpenSRO не «увидит» сертификат, если вышел срок его действия.

Структура контейнера ключа

Столкнулся с проблемой восстановления контейнеров ключей записанных на флешке. Отформатировали флеху и пытались восстановить ключи. Восстановили кучу файлов *.key с именами отличающимися цифрами, скорее всего индикатор разных папок (контейнеров).
Записали это все на флешку обратно, убив возможность дальнейших экспериментов по восстановлению.
Имеем папку с кучей фалов. Пытаюсь собрать контейнеры по цифрам, допустим так:
masks_53.key
primary_53.key
header_53.key
masks2_53.key
primary2_53.key
name_53.key
но крипто-про контейнер не видит.

Кто знает как и чем можно посмотреть данные файлы? Если это текстовые файлы, то в какой кодировке должны быть?
Допустим файл name.key просматривался текстовым редактором и можно было прочитать имя КП.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 1935
  • Спасибо получено: 520

11 дек 2015 14:38 #1352 от Alex67
Alex67 ответил в теме Структура контейнера ключа

А убрать _53 все равно не видит?
Имена файлов в контейнере такие:
571 header.key
56 masks.key
56 masks2.key
44 name.key
36 primary.key
36 primary2.key

«Кто людям помогает — лишь тратит время зря. Хорошими делами прославиться нельзя» (с) Шапокляк

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 386
  • Спасибо получено: 94

11 дек 2015 15:03 #1353 от sedkazna
sedkazna ответил в теме Структура контейнера ключа

Alex67, да убирал _53, результат одинаков.
Это что за числа перед именами фалов поставил? Вроде без цифр контейнер генерируется.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 1935
  • Спасибо получено: 520

11 дек 2015 16:38 — 11 дек 2015 16:49 #1354 от Alex67
Alex67 ответил в теме Структура контейнера ключа

sedkazna пишет: Это что за числа перед именами фалов поставил? Вроде без цифр контейнер генерируется.

Это не я — это команда dir , размер файла в байтах.
Скорее всего восстановить не получится. Сколько ж там было ключей — неужто 52? Зато приучатся делать копию контейнера.
Это всё еще и в папке вида ympugejg.000 должно лежать можно ympugejg.001 и т.д. по номерам.
Если только в блокноте посмотреть name.key сгенерить на другой машине на то же имя, посмотреть как называется папка и засунуть файлики туда, но надежды мало.

«Кто людям помогает — лишь тратит время зря. Хорошими делами прославиться нельзя» (с) Шапокляк

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 386
  • Спасибо получено: 94

11 дек 2015 16:44 #1355 от sedkazna
sedkazna ответил в теме Структура контейнера ключа

:blink:

Ключей было гораздо меньше, но куча неудачных ЭП не верно сгенерированных начиная с 2011 г. несколько подведомтсвенных организаций и все это вылилось в подобные цифры. Плюс Континет-АП. Плюс Калуга-Астрал. Короче полный швах!

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 1935
  • Спасибо получено: 520

11 дек 2015 17:01 — 11 дек 2015 17:12 #1356 от Alex67
Alex67 ответил в теме Структура контейнера ключа

Ёперный театр! Не факт, что все файлики с индексом _52 лежали в одной ключевой папке.
Не знаю как Астрал , а у Континентовского в name.key вообще понятного имени нет ЕМНИП
На днях видал — больничка приносила флешку с ключами и запросами, так у них там . кхм. эротические фильмы записаны — видимо чтобы место на флешке зря не пропадало.
Причем у меня была вставлена другая флешка — делаю безопасное извлечение — она не извлекается —
Я: (Бормочу себе под нос) -: Так, это что еще за хрень?
Девушка — Где хрень? У меня на флешке?
Я -Нет, это я про другое.
Вставляю, а у них там . это.
Угадал не глядя одним словом

«Кто людям помогает — лишь тратит время зря. Хорошими делами прославиться нельзя» (с) Шапокляк

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 386
  • Спасибо получено: 94

11 дек 2015 17:04 #1357 от sedkazna
sedkazna ответил в теме Структура контейнера ключа

:)

Alex67 пишет: так у них там . кхм. эротические фильмы записаны — видимо чтобы место на флешке зря не пропадало.

:whistle:

С медсестрами?

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Меньше Больше

  • Сообщений: 2409
  • Спасибо получено: 405

12 дек 2015 13:21 — 12 дек 2015 21:33 #1359 от Alex_04
Alex_04 ответил в теме Структура контейнера ключа

sedkazna пишет: Кто знает как и чем можно посмотреть данные файлы? Если это текстовые файлы, то в какой кодировке должны быть?

:)

Файлы наверняка текстовые, но думаю в зашифрованном виде, ведь в них те самые «закрытые ключи подписи». Тут крипта постаралась максимально осложнить возможность любому желающему просто и открыто их посмотреть. Я не супер хакер, потому и не заморачиваюсь.

Alex67 пишет: Если только в блокноте посмотреть name.key сгенерить на другой машине на то же имя, посмотреть как называется папка и засунуть файлики туда, но надежды мало.

Имхо — ее вообще нет, ведь надо угадать с точностью до секунды время генерации (ниже описал «расшифровку» содержания name.key), и процесс не зря называется «генерация», во время которого мышь гоняем и по клаве бацаем в произвольном порядке.

Alex67 пишет: у Континентовского в name.key вообще понятного имени нет

Ну отчего же, в Континентовском name.key, сгенерированном в самом Континенте,следующая инфа:
Имя учетной записи пользователя компьютера__ДД_ММ_ГГГГ__ЧЧ_ММ_СС_. генерации запроса,
. — какое-то число, возможно чисто произвольное, «случайное», закономерность не уловил.
В казначейских name.key во всех схожая инфа:
Фамилия Имя Отчество заявителя ММДДЧЧММСС генерации запроса (без года).

Не факт, что все файлики с индексом _52 лежали в одной ключевой папке.

;)

Да ктож их разберет теперь после восстановления кто где был. Вот и живой пример к вопросу надо ли буквально понимать и исполнять регламент, когда он требует иметь только 1 ключ подписи на носителе. Что выбирать: перетыкание флэшек или потеря всех ЭП разом?

«Мы будем жить плохо, но недолго.» (© Черномырдин В.С.)

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Термины

Часть терминов в статье подается в упрощенном виде для простоты понимания.

Используя термин ЭП, мы подразумеваем квалифицированную электронную подпись (КЭП). Это электронная подпись, которая полностью соответствует всем требованиям 63-ФЗ и Приказу ФСБ России № 796 к средствам ЭП и хранится на персональном защищенном ключевом носителе.

Ключи ЭП — закрытый и открытый ключи, которые вместе составляют ключевую пару. Создание (генерация) ключевой пары выполняется криптографическим программным обеспечением , оно может быть установлено в точке выдачи УЦ, у вас на компьютере и в самом ключевом носителе.
Закрытый ключ никому разглашать нельзя. Если его кто-то узнал, то он может подписать любой документ от вашего имени.
Открытый ключ можно показывать всем. Его значение (это просто длинное число) заносится в сертификат ключа проверки электронной подписи (он же просто «сертификат»), который потом используется при проверке вашей подписи под документом.

Сертификат ЭП выдает Удостоверяющий Центр (УЦ). Форма сертификата КЭП соответствует требованиям Приказа ФСБ РФ № 795. Главная задача УЦ — достоверно определить, что вы – это вы. Для того, чтобы при обмене документами в электронном виде люди точно знали, что подпись, сделанная с использованием вашего сертификата — поставлена именно вами.

Ключи ЭП вместе с сертификатом составляют контейнер ЭП (ключевой контейнер).

Разновидность ключей электронной подписи

Извлекаемые ключи («пассивные контейнеры»)

Создаются с помощью программного ГОСТ-криптопровайдера, который устанавливается в операционную систему (ОС).

Контейнеры ГОСТ-криптопровайдеров можно хранить в виде файлов на флеш-накопителях, жестком диске и реестре компьютера или на специализированном ключевом носителе, защищенном PIN-кодом.

Когда ключевые контейнеры хранятся как обычные файлы, возможности анализа, копирования или удаления никак не ограничены, а значит скопировать и удалить их может кто угодно. Поэтому безопаснее хранить ключевые контейнеры на специализированном, защищенном ключевом носителе (смарт-карте или токене), защищенном PIN-кодом. Именно этот вариант мы и будем рассматривать дальше.

Чтобы криптопровайдер (СКЗИ) смог получить доступ к содержимому защищенного ключевого носителя, нужно физически иметь в распоряжении ключевой носитель и знать PIN-код. Все операции с закрытым ключом выполняются в оперативной памяти компьютера.

Т. е. во время операций с закрытым ключом, после ввода правильного PIN-кода, закрытый ключ временно извлекается в оперативную память компьютера.

Таким образом, извлекаемые экпортируемые ключи — это ключи, которые можно скопировать на другой носитель средствами программного криптопровайдера.

А извлекаемые неэкспортируемые ключи — это ключи с запретом копирования стандартными средствами программного криптопровайдера.

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

Неизвлекаемые ключи («активные контейнеры»)

Создаются с использованием встроенных аппаратных криптографических механизмов внутри специализированных ключевых носителей. Для генерации ключей используется криптографическое ядро внутри микроконтроллера устройства. Такие ключи ЭП хранятся не просто в защищенной памяти с доступом по PIN-коду, но и в специальном типе файлов, с которым умеет работать только криптоядро устройства. При работе с подписью все операции производятся внутри токена, и закрытый ключ никогда не копируется из памяти микроконтроллера.

Неизвлекаемые ключи бывают разного формата: PKCS#11 и “ФКН-ключ” .

Используя стандартизированный программный интерфейс (API) библиотеки PKCS#11, приложение, или программный криптопровайдер, напрямую работает с криптоядром ключевого носителя.

У носителей, которые называются ФКН (функциональный ключевой носитель) есть возможность работать с неизвлекаемыми “ФКН-ключами”. Такие носители и криптопровайдер на компьютере, для передачи PIN-кода и другого обмена (в т.ч. данными, которые подписываются), строят защищенный канал. Для этого используется протокол SESPAKE ( протокол выработки общего ключа с аутентификацией на основе пароля). Выработка ключа — задача устройства ФКН и криптопровайдера на компьютере, поэтому на компьютере также должна быть установлена версия КриптоПро CSP, поддерживающая SESPAKE.

Неэкспортируемый ключ неизвлекаемый ключ .

Неэкспортируемые ключи ЭП ненадолго извлекаются в оперативную память компьютера при работе с ними программного криптопровайдера. При этом копирование неизвлекаемых ключей полностью исключено.

Доступ к закрытому ключу

Для доступа к ключевому контейнеру при работе с любыми защищенными ключевыми носителями обязательно требуется ввести правильный PIN-код Пользователя . PIN-код может не быть длинным и сложным – это компенсируется требованием физического владения устройством и ограничениями на перебор PIN-кода. После определенного количества неудачных попыток ввода PIN-кода доступ к содержимому токена или смарт-карты блокируется. Это защищает от случайного подбора PIN-кода. Очень важно установить уникальный PIN-код, который будет сложно подобрать.

Теперь поговорим о том, какие бывают ключевые носители.

Виды защищенных ключевых носителей

Пассивные ключевые носители

Выступают в роли защищенного хранилища для извлекаемых ключей. То есть программный криптопровайдер генерирует ключи, записывает их в защищенную PIN-кодом память устройства и впоследствии работает с ними. Пример такого носителя – Рутокен Lite .

Активные ключевые носители

Могут выступать в роли пассивного ключевого носителя, что снижает безопасность использования ключа ЭП. Но главное их отличие в том, что они являются самостоятельным СКЗИ, если использовать функции аппаратного криптоядра устройства — встроенного микрокомпьютера. Ключи сгенерированные в криптоядре — неизвлекаемые и вся работа с закрытым ключом (в т. ч. формирование ЭП) будет производиться внутри носителя. Активные ключевые носители еще называют криптографическими ключевыми носителям

Пример активного носителя — Рутокен ЭЦП 3.0 3220 .

Функциональный ключевой носитель (ФКН)

Это активный носитель, дополнительно имеющий реализацию протокола SESPAKE для построения защищенного канала между криптопровайдером и токеном.

Пример такого устройства — Рутокен ЭЦП 3.0 3220 , который также поддерживает активный и пассивный режимы.

1) Криптографические возможности активных и ФКН-носителей встроенный КриптоПро CSP. Если требуется работа с КриптоПро CSP, нужно приобрести лицензию на этот продукт. Вне зависимости от вида ключевого носителя и формата ключей ЭП на нем.

2) Конвертация ключей из одного формата в другой невозможна. Если ключи были созданы извлекаемыми, то их нельзя перевести в формат неизвлекаемых ключей и наоборот.

Средства генерации ключевых пар

Рассмотрим с помощью каких средств криптографической защиты информации (СКЗИ) можно генерировать и использовать разные форматы ключей, на примере устройств Рутокен:

Извлекаемые ключи («пассивные контейнеры»)

  • СКЗИ КриптоПро CSP версии 4.0 и новее . При генерации нужно выбрать «режим CSP». Ключи будут созданы в защищённой памяти любой из моделей Рутокен.
  • При использовании СКЗИ VipNet CSP или Signal-COM CSP , режим выбирать не надо: извлекаемые ключи будут созданы на пассивных ключевых носителях.

Неизвлекаемые ключи («активные контейнеры»)

Генерируются на активных и ФКН носителях, с использованием стандартизированного программного интерфейса (API) библиотеки PKCS#11.
Например, вся линейка продуктов Рутокен ЭЦП 3.0 содержит в себе возможности аппаратной криптографии.

Для генерации ключей формата PKCS#11 можно использовать инструменты от компании Актив:

  • Генератор запроса на сертификат из комплекта Драйверов Рутокен.
  • Рутокен SDK, содержащий примеры использования кроссплатформенной библиотеки rtpkcs11ecp).

Или воспользоваться программными ГОСТ-криптопровайдерами:

  • СКЗИ КриптоПро CSP версии 5.0 R2и новее — при генерации ключей надо выбрать режим «Активный токен».
  • СКЗИ Signal-COM CSP или VipNet CSP — на активные ключевые носители из линейки Рутокен ЭЦП 3.0 автоматически генерируются неизвлекаемые ключи.

ФКН-ключи

Для того, чтобы сгенерировать ключи ФКН с защитой канала нужно использовать модели линейки Рутокен ЭЦП 3.0 — именно эти модели имеют поддержку протокола SESPAKE. Важно так же, что для работы и генерации ключей в таком формате подойдет версия КриптоПро CSP 5.0 и новее .

Сертификация устройств

Немного о сертификации ключевых носителей.

Для того, чтобы электронная подпись юридически считалась квалифицированной, средство криптографической защиты информации (СКЗИ), с помощью которого производится генерация ключей и последующая работа с ключами ЭП, должно быть сертифицировано в ФСБ России.

Чтобы проще было запомнить:

  • ФСТЭК России сертифицирует средство защиты информации (устройство).
  • ФСБ России сертифицирует средство криптографической защиты информации (СКЗИ).

Таким образом, в случае с извлекаемыми ключами , сгенерированными с помощью программного СКЗИ, в ФСБ России должен быть сертифицирован именно программный ГОСТ-криптопровайдер. А пассивный носитель Рутокен должен быть сертифицирован во ФСТЭК России.

В случае с неизвлекаемыми ключами на активном или ФКН-носителе, так как при генерации ключей используется аппаратная криптография, сертифицированным в ФСБ России должен сам носитель.

Заключение

Для надежной защиты ключей ЭП от копирования и перехвата мы рекомендуем использовать активные носители с возможностью генерации неизвлекаемых ключей на «борту», такие как Рутокен ЭЦП 3.0 3220 . Так ваша электронная подпись будет максимально защищена.

Читаем контейнер закрытого ключа КриптоПро средствами OpenSSL

Речь пойдет о файлах primary.key, masks.key и header.key, которые лежат в директории ххххх.000 на флешке. Данные файлы входят в состав криптоконтейнера закрытого ключа электронной подписи криптопровайдера КриптоПро, формат которого нигде не опубликован. Целью данной статьи является чтение контейнера и преобразование закрытого ключа в формат, который может быть прочитан в библиотеке OpenSSL. Долгое время было распространено ошибочное суждение, что достаточно сделать нечто вида (primary_key XOR masks_key) и мы получим закрытый ключ в чистом (raw) виде, однако забегая вперед, можно утверждать, что в КриптоПро было применено более сложное преобразование, в худшем случае состоящее из более чем 2000 (двух тысяч) операций хеширования.

  • Читает контейнер не напрямую, а через криптопровайдер, поэтому там, где кроме OpenSSL ничего нет, не работает.
  • Если в свойствах ключа не отмечено, что ключ «экспортируемый», то конвертировать его невозможно.
  • В демо версии не формирует файл с ключом, эта возможность присутствует только в платной версии.

Файл primary.key

Содержит 32 байта ключа в формате Asn1. Это только половина ключа, полный ключ получается при делении этого числа по модулю Q на маску. Поле, хранящее модуль Q в библиотеке OpenSSL имеет название order. Маска лежит в файле masks.key:

primary.key

Файл masks.key

Содержит 32 байта маски ключа в формате Asn1, зашифрованного на ключе хранения pwd_key. Далее 12 байт «затравочной» информации для генерации ключа хранения pwd_key, если криптоконтейнер защищен паролем, то пароль также участвует в генерации ключа хранения.

Далее контрольная сумма (имитозащита) 4 байта. Контрольной информацией для простоты мы пользоваться не будем, общий контроль будет осуществляться путем генерации открытого ключа и сравнения первых 8 байт полученного ключа с соответствующим полем из файла header.key:

masks.key

Файл header.key

  • GostR3410_2001_CryptoPro_A_ParamSet — 1.2.643.2.2.35.1
  • GostR3410_2001_CryptoPro_B_ParamSet — 1.2.643.2.2.35.2
  • GostR3410_2001_CryptoPro_C_ParamSet — 1.2.643.2.2.35.3
  • GostR3410_2001_CryptoPro_XchA_ParamSet — 1.2.643.2.2.36.0
  • GostR3410_2001_CryptoPro_XchB_ParamSet — 1.2.643.2.2.36.1

header.key

Читаем закрытый ключ и конвертируем

Файл privkey.c

#include #include #include #include #include #include #include "gost_lcl.h" /* Convert little-endian byte array into bignum */ BIGNUM *reverse32bn(char *b, BN_CTX *ctx) < BIGNUM *res; char buf[32]; BUF_reverse(buf, b, 32); res = BN_bin2bn(buf, 32, BN_CTX_get(ctx)); OPENSSL_cleanse(buf, sizeof(buf)); return res; >void xor_material(char *buf36, char *buf5C, char *src) < int i; for(i = 0; i < 32; i++) < buf36[i] = src[i] ^ 0x36; buf5C[i] = src[i] ^ 0x5C; >> int make_pwd_key(char *result_key, char *start12, int start12_len, char *passw) < int result; int i; char pincode4[1024]; int pin_len; char current[32]; char material36[32]; char material5C[32]; char hash_result[32]; gost_hash_ctx ctx; init_gost_hash_ctx(&ctx, &GostR3411_94_CryptoProParamSet); memset(pincode4, 0, sizeof(pincode4)); pin_len = strlen(passw); if (pin_len*4 >sizeof(pincode4)) < result = 1; goto err; >for(i = 0; i < pin_len; i++) pincode4[i*4] = passw[i]; start_hash(&ctx); hash_block(&ctx, start12, start12_len); if (pin_len) hash_block(&ctx, pincode4, pin_len * 4); finish_hash(&ctx, hash_result); memcpy(current, (char*)"DENEFH028.760246785.IUEFHWUIO.EF", 32); for(i = 0; i < (pin_len?2000:2); i++) < xor_material(material36, material5C, current); start_hash(&ctx); hash_block(&ctx, material36, 32); hash_block(&ctx, hash_result, 32); hash_block(&ctx, material5C, 32); hash_block(&ctx, hash_result, 32); finish_hash(&ctx, current); >xor_material(material36, material5C, current); start_hash(&ctx); hash_block(&ctx, material36, 32); hash_block(&ctx, start12, start12_len); hash_block(&ctx, material5C, 32); if (pin_len) hash_block(&ctx, pincode4, pin_len * 4); finish_hash(&ctx, current); start_hash(&ctx); hash_block(&ctx, current, 32); finish_hash(&ctx, result_key); result = 0; //ok err: return result; > BIGNUM *decode_primary_key(char *pwd_key, char *primary_key, BN_CTX *bn_ctx) < BIGNUM *res; char buf[32]; gost_ctx ctx; gost_init(&ctx, gost_cipher_list->sblock); gost_key(&ctx, pwd_key); gost_dec(&ctx, primary_key, buf, 4); res = reverse32bn(buf, bn_ctx); OPENSSL_cleanse(buf, sizeof(buf)); return res; > BIGNUM *remove_mask_and_check_public(char *oid_param_set8, BIGNUM *key_with_mask, BIGNUM *mask, char *public8, BN_CTX *ctx) < int result; EC_KEY *eckey = NULL; const EC_POINT *pubkey; const EC_GROUP *group; BIGNUM *X, *Y, *order, *raw_secret, *mask_inv; char outbuf[32], public_X[32]; ASN1_OBJECT *obj; int nid; order = BN_CTX_get(ctx); mask_inv = BN_CTX_get(ctx); raw_secret = BN_CTX_get(ctx); X = BN_CTX_get(ctx); Y = BN_CTX_get(ctx); if (!order || !mask_inv || !raw_secret || !X || !Y) < result = 1; goto err; >obj = ASN1_OBJECT_create(0, oid_param_set8+1, *oid_param_set8, NULL, NULL); nid = OBJ_obj2nid(obj); ASN1_OBJECT_free(obj); if (!(eckey = EC_KEY_new())) < result = 1; goto err; >if (!fill_GOST2001_params(eckey, nid)) < result = 1; goto err; >if (!(group = EC_KEY_get0_group(eckey))) < result = 1; goto err; >if (!EC_GROUP_get_order(group, order, ctx)) < result = 1; goto err; >if (!BN_mod_inverse(mask_inv, mask, order, ctx)) < result = 1; goto err; >if (!BN_mod_mul(raw_secret, key_with_mask, mask_inv, order, ctx)) < result = 1; goto err; >if (!EC_KEY_set_private_key(eckey, raw_secret)) < result = 1; goto err; >if (!gost2001_compute_public(eckey)) < result = 1; goto err; >if (!(pubkey = EC_KEY_get0_public_key(eckey))) < result = 1; goto err; >if (!EC_POINT_get_affine_coordinates_GFp(group, pubkey, X, Y, ctx)) < result = 1; goto err; >store_bignum(X, outbuf, sizeof(outbuf)); BUF_reverse(public_X, outbuf, sizeof(outbuf)); if (memcmp(public_X, public8, 8) != 0) < result = 1; goto err; >result = 0; //ok err: if (eckey) EC_KEY_free(eckey); if (result == 0) return raw_secret; return NULL; > int file_length(char *fname) < int len; FILE *f = fopen(fname, "rb"); if (f == NULL) return -1; fseek(f, 0, SEEK_END); len = ftell(f); fclose(f); return len; >int read_file(char *fname, int start_pos, char *buf, int len) < int read_len; FILE *f = fopen(fname, "rb"); if (f == NULL) return 1; if (start_pos) fseek(f, start_pos, SEEK_SET); read_len = fread(buf, 1, len, f); fclose(f); if (read_len != len) return 1; return 0; //ok >int get_asn1_len(unsigned char *buf, int *size_hdr) < int n, i, res; int pos = 0; if ((buf[pos]&0x80) == 0) < *size_hdr = 1; return buf[pos]; >n = buf[pos++]&0x7f; res = 0; for(i = 0; i < n; i++) < res = res*256 + buf[pos++]; >*size_hdr = n+1; return res; > #define MAX_HEADER 20000 int read_container(char *fpath, int flag2, char *salt12, char *primary_key, char *masks_key, char *public8, char *oid_param_set8) < int result; char primary_path[1024+30]; char masks_path[1024+30]; char header_path[1024+30]; char header_buf[MAX_HEADER]; int header_len; int i, len, pos, size_hdr; if (strlen(fpath)>1024) < result = 1; goto err; >sprintf(header_path, "%s/header.key", fpath); if (flag2 == 0) < sprintf(primary_path, "%s/primary.key", fpath); sprintf(masks_path, "%s/masks.key", fpath); >else < sprintf(primary_path, "%s/primary2.key", fpath); sprintf(masks_path, "%s/masks2.key", fpath); >if (read_file(primary_path, 4, primary_key, 32)) < result = 1; goto err; >if (read_file(masks_path, 4, masks_key, 32)) < result = 1; goto err; >if (read_file(masks_path, 0x26, salt12, 12)) < result = 1; goto err; >header_len = file_length(header_path); if (header_len < 0x42 || header_len >MAX_HEADER) < result = 1; goto err; >if (read_file(header_path, 0, header_buf, header_len)) < result = 1; goto err; >//------------- skip certificate --------------------------- pos = 0; for(i = 0; i < 2; i++) < get_asn1_len(header_buf+pos+1, &size_hdr); pos += size_hdr+1; if (pos >header_len-8) < result = 2; goto err; >> //------------------ get oid_param_set8 ----------------------- #define PARAM_SET_POS 34 if (memcmp(header_buf+pos+PARAM_SET_POS, "\x6\x7", 2) != 0) < result = 2; goto err; >memcpy(oid_param_set8, header_buf+pos+PARAM_SET_POS+1, 8); //------------------ get public8 ----------------------- result = 2; //not found pos += 52; for(i = 0; i < 3; i++) < len = get_asn1_len(header_buf+pos+1, &size_hdr); if (len == 8 && memcmp(header_buf+pos, "\x8a\x8", 2) == 0) < memcpy(public8,header_buf+pos+2,8); result = 0; //ok break; >pos += len+size_hdr+1; if (pos > header_len-8) < result = 2; goto err; >> err: OPENSSL_cleanse(header_buf, sizeof(header_buf)); return result; > #define START_OID 0x12 #define START_KEY 0x28 unsigned char asn1_private_key[72] = < 0x30,0x46,2,1,0,0x30,0x1c,6,6,0x2a,0x85,3,2,2,0x13,0x30,0x12,6,7,0x11, 0x11,0x11,0x11,0x11,0x11,0x11,6,7,0x2a,0x85,3,2,2,0x1e,1,4,0x23,2,0x21,0 >; int main(int argc, char **argv) < int result; char *container_path; char *passw; char salt12[12]; char primary_key[32]; char masks_key[32]; char public8[8]; char oid_param_set8[8]; BN_CTX *ctx; BIGNUM *key_with_mask; BIGNUM *mask; BIGNUM *raw_key; char pwd_key[32]; char outbuf[32]; ctx = BN_CTX_new(); if (argc == 2) < container_path = argv[1]; passw = ""; >else if (argc == 3) < container_path = argv[1]; passw = argv[2]; >else < printf("get_private container_path [passw]\n"); result = 1; goto err; >if (read_container(container_path, 0, salt12, primary_key, masks_key, public8, oid_param_set8) != 0 && read_container(container_path, 1, salt12, primary_key, masks_key, public8, oid_param_set8) != 0) < printf("can not read container from %s\n", container_path); result = 2; goto err; >make_pwd_key(pwd_key, salt12, 12, passw); key_with_mask = decode_primary_key(pwd_key, primary_key, ctx); OPENSSL_cleanse(pwd_key, sizeof(pwd_key)); mask = reverse32bn(masks_key, ctx); raw_key = remove_mask_and_check_public(oid_param_set8, key_with_mask, mask, public8, ctx); if (raw_key) < BIO *bio; store_bignum(raw_key, outbuf, sizeof(outbuf)); memcpy(asn1_private_key+START_OID, oid_param_set8, 8); memcpy(asn1_private_key+START_KEY, outbuf, 32); //bio = BIO_new_file("private.key", "w"); bio = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT); PEM_write_bio(bio, "PRIVATE KEY", "", asn1_private_key, sizeof(asn1_private_key)); BIO_free(bio); OPENSSL_cleanse(outbuf, sizeof(outbuf)); OPENSSL_cleanse(asn1_private_key, sizeof(asn1_private_key)); result = 0; //ok >else < printf("Error check public key\n"); result = 3; >err: BN_CTX_free(ctx); OPENSSL_cleanse(salt12, sizeof(salt12)); OPENSSL_cleanse(primary_key, sizeof(primary_key)); OPENSSL_cleanse(masks_key, sizeof(masks_key)); return result; > 

Основную работу выполняют следующие 3 функции:

1. Создаем ключ хранения исходя из 12-ти байтовой «соли» и пароля.

make_pwd_key(pwd_key, salt12, 12, passw); 

2. Расшифровываем основной ключ на ключе хранения.

key_with_mask = decode_primary_key(pwd_key, primary_key, ctx); 

3. Делим ключ с маской на маску.

raw_key = remove_mask_and_check_public(oid_param_set8, key_with_mask, mask, public8, ctx); 

Но так как в библиотеке OpenSSL операция деления по модулю традиционно отсутствует, пользуемся операцией взятия обратного числа и умножением.

if (!BN_mod_inverse(mask_inv, mask, order, ctx)) < result = 1; goto err; >if (!BN_mod_mul(raw_secret, key_with_mask, mask_inv, order, ctx))

Сборка утилиты конвертирования ключа

Далее сборка исходников описана для Linux версии.

Версию для Windows можно скачать отсюда там же есть сертификаты и закрытый ключ для тестирования, для сборки потребуется бесплатный компилятор Borland C++ 5.5

Компиляция OpenSSL библиотеки

После скачивания и распаковки исходных текстов openssl в целевой директории выполняем команды:

./config make 

Получаем готовую библиотеку libcrypto.a в текущей директории.
Также потребуются заголовочные файлы из директорий engines/ccgost и include.

Компиляция privkey.c

gcc -o privkey -Iengines/ccgost -Iinclude privkey.c libcrypto.a -pthread -ldl 

Формирование файла закрытого ключа private.key

./privkey /mnt/usbflash/lp-9a0fe.000 

Тестовый закрытый ключ в криптоконтейнере lp-9a0fe.000, сертификат открытого ключа signer.cer и другие файлы для тестирования можно взять отсюда

Получаем результат работы:

-----BEGIN PRIVATE KEY----- MEYCAQAwHAYGKoUDAgITMBIGByqFAwICJAAGByqFAwICHgEEIwIhAKzsrv/l1Uwk uzph/LQN9mux0Jz0yaW21kOYEFv0Xyut -----END PRIVATE KEY----- 

Cохраняем в private.key

Пользуемся закрытым ключом private.key для подписывания файла file.txt

openssl cms -sign -inkey private.key -in file.txt -CAfile CA.cer -signer signer.cer -engine gost -out test.sign -outform DER -noattr -binary 

Проверяем подпись

openssl cms -verify -content file.txt -in test.sign -CAfile CA.cer -signer signer.cer -engine gost -inform DER -noattr -binary 

Все работает просто замечательно!

Спасибо за внимание. Это была моя первая статья на хабре.

  • криптопро
  • криптопровайдер
  • закрытый ключ

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *