Перейти к основному содержимому
Версия: 4.6.X

Шифрование токеном JaCarta

Бэкенд --cipher jacarta шифрует резервные копии с привязкой к аппаратному токену JaCarta. Для каждого блоба генерируется свой ключ данных (DEK), который оборачивается по схеме VKO на ЭК-ключе ГОСТ Р 34.10-2012, хранящемся на токене. Поток данных шифруется «Кузнечиком» (kuznyechik-ctr) и защищается имитовставкой HMAC-Стрибог-256, проверяемой до любых разрушающих действий при восстановлении.

Ключевые свойства:

  • Создание копии не требует токена — достаточно открытого ключа получателя (public_key_pem).
  • Восстановление требует токен (через сайдкар komrad-jacarta) или escrow-фразу — аварийный доступ без токена.
  • Закрытый ключ никогда не покидает токен; PIN не появляется в аргументах процессов.

Ключевой материал: комплект на каждый блоб

Ключевой материал вырабатывается для каждого блоба, а не один раз на набор копий. При создании копии для каждого блоба выполняется:

  • генерация случайного DEK (32 байта) и вывод ключа имитовставки HMAC-Стрибог-256(DEK, "mac");
  • генерация эфемерной ключевой пары ГОСТ Р 34.10-2012 (openssl genpkey) и вывод KEK по схеме VKO на открытом ключе получателя (openssl pkeyutl -derive) — программно, токен при этом не нужен;
  • обёртывание DEK под KEK («Кузнечик» в режиме CFB);
  • построение escrow-блока: scrypt (N = 32768, r = 8, p = 1) над cipher.escrow.passphrase — если escrow-фраза задана.

Набор из N блобов, таким образом, содержит N независимых DEK, N эфемерных открытых ключей и (при заданном escrow) результаты N вычислений scrypt.

Что это значит при восстановлении

komrad-cli restore работает в две фазы, и каждая фаза открывает каждый блоб заново:

  1. Фаза 1 — проверка. Движок прогоняет каждый выбранный блоб через расшифровку до конца потока и сверяет имитовставку. Расшифрованные данные отбрасываются.
  2. Фаза 2 — применение. Поверхности читают те же блобы ещё раз, уже для записи в систему.

Каждое открытие блоба — это один вызов сайдкара komrad-jacarta decrypt-dek, то есть одно обращение к токену (VKO на закрытом ключе токена). Полное восстановление набора из N блобов выполняет 2N обращений к токену: N в фазе проверки и N в фазе применения.

warning

Токен должен оставаться подключённым и разблокированным всё время восстановления, а не только в его начале. Извлечение токена после фазы проверки прервёт восстановление на фазе применения.

Флаг --only сокращает N: обе фазы используют один и тот же отбор поверхностей, поэтому --only postgres пропорционально уменьшает число обращений к токену.

Вычисления scrypt при восстановлении по умолчанию не выполняются вовсе: подбор DEK останавливается сразу после успешного ответа токена и к escrow-блоку не обращается. scrypt считается только тогда, когда escrow-путь действительно используется.

Требования

  • Astra Linux с ГОСТ-движком OpenSSL (libgost-astra).
  • Библиотека PKCS#11 JaCarta (например, /usr/lib/libjcPKCS11-2.so).
  • Бинарь-сайдкар komrad-jacarta (входит в поставку KOMRAD) — нужен на узле восстановления.

Подготовка токена

Сгенерируйте ключевую пару ГОСТ Р 34.10-2012 на токене и выгрузите открытый ключ:

export KOMRAD_JACARTA_PIN='PIN_токена'
komrad-jacarta init-key \
--module /usr/lib/libjcPKCS11-2.so \
--token-label KOMRAD-BACKUP \
--key-label komrad-backup-key \
--paramset TCA \
--pubkey-out /etc/echelon/komrad/keys/backup_gost.pem

--paramset — параметры кривой: TCA (умолчание), A, B.

Если ключ уже создан на токене, выгрузите только открытый ключ:

komrad-jacarta import-key \
--module /usr/lib/libjcPKCS11-2.so \
--token-label KOMRAD-BACKUP \
--key-label komrad-backup-key \
--pubkey-out /etc/echelon/komrad/keys/backup_gost.pem

PIN передаётся сайдкару только через переменную окружения KOMRAD_JACARTA_PIN.

Конфигурация

Бэкенд настраивается только через komrad-backup.yaml (--config):

cipher:
backend: jacarta
jacarta:
module: /usr/lib/libjcPKCS11-2.so
token_label: KOMRAD-BACKUP
user_pin: ${JACARTA_PIN}
key_label: komrad-backup-key
public_key_pem: /etc/echelon/komrad/keys/backup_gost.pem
agent_path: /opt/echelon/komrad/bin/komrad-jacarta
escrow:
passphrase: ${BACKUP_ESCROW}

escrow.passphrase — необязательная аварийная фраза: ею дополнительно оборачивается DEK, чтобы копию можно было восстановить при утере токена. Храните её отдельно от копий.

warning

cipher.escrow.passphrase в конфиге — единственный способ задать escrow-секрет при создании копии. Для бэкенда jacarta команда backup create флаг --passphrase не использует: он игнорируется, escrow-блок из него не строится.

Если при создании копии escrow-фраза не была задана, escrow-блок в блобы не записывается вовсе, и восстановить их без токена уже нельзя — добавить escrow задним числом невозможно.

При восстановлении --passphrase работает как запасной вариант, а не как переопределение: он трактуется как escrow-фраза только тогда, когда cipher.escrow.passphrase в конфиге не задан. Если фраза задана в конфиге, побеждает она.

Создание копии

komrad-cli backup create \
--cipher jacarta \
--config /etc/echelon/komrad/komrad-backup.yaml \
--to /var/backups/komrad

Токен при этом не нужен — используется только открытый ключ. Флаг --passphrase бэкендом игнорируется; escrow-секрет задаётся только через cipher.escrow.passphrase в конфиге. В манифест записывается только метка ключа (key_label); параметры модуля, токена и escrow в манифест не попадают.

Проверка

komrad-cli backup verify /var/backups/komrad/20260630T120000Z \
--config /etc/echelon/komrad/komrad-backup.yaml
примечание

Для JaCarta-копий verify проверяет только контрольные суммы sha256. Полная проверка имитовставки (HMAC) выполняется при restore — до применения данных.

Восстановление

С токеном (PIN — в cipher.jacarta.user_pin):

sudo komrad-cli restore /var/backups/komrad/20260630T120000Z \
--config /etc/echelon/komrad/komrad-backup.yaml

Без токена — по escrow-фразе:

sudo komrad-cli restore /var/backups/komrad/20260630T120000Z \
--config /etc/echelon/komrad/komrad-backup.yaml \
--passphrase "аварийная_фраза"

Если cipher.escrow.passphrase в конфиге не задан, --passphrase трактуется как escrow-фраза.

Проверка перед записью (verify_before_write)

cipher:
jacarta:
verify_before_write: true
scratch_dir: /var/tmp/komrad-restore

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

verify_before_write: true меняет механику: блоб сначала целиком выгружается во временный файл, затем по этим же байтам сверяется имитовставка — сперва с DEK от токена, а при несовпадении с escrow-DEK, — и только после успешной сверки вызывающая сторона получает первый байт открытого текста.

Что режим даёт сверх штатной фазы проверки:

  • Откат на escrow, когда токен вернул «правильный, но не тот» DEK. Штатный потоковый путь запрашивает DEK у токена и, получив успешный ответ, к escrow больше не обращается. Проверка перед записью пробует обоих кандидатов по одним и тем же байтам — это единственный работающий путь восстановления в сценарии из раздела Диагностика.
  • Закрытие разрыва между фазами. Фаза проверки и фаза применения читают блоб из хранилища двумя разными обращениями; при проверке перед записью проверяются и расшифровываются гарантированно одни и те же байты.
  • Защиту для потребителей вне движка восстановления, которые вызывают расшифровку напрямую и своей фазы проверки не имеют.

Цена:

  • Двойная выгрузка. Блоб сначала пишется во временный файл, затем читается из него повторно — для сверки имитовставки и ещё раз для расшифровки.
  • Место на диске. Требуется место под самый крупный отдельный блоб, а не под весь набор: временный файл создаётся и освобождается для каждого блоба по очереди. Каталог задаётся параметром scratch_dir (по умолчанию — системный TMPDIR).
примечание

Временный файл отвязывается от каталога (unlink) до записи первого байта шифртекста: имени в файловой системе у него нет, все шаги работают с одним и тем же файловым дескриптором, а место освобождается ядром при его закрытии — в том числе после аварийного завершения процесса.

Диагностика: «HMAC-Streebog-256 verification failed»

При восстановлении JaCarta-копии возможна ошибка вида:

jacarta: HMAC-Streebog-256 verification failed: the archive may be corrupt or tampered
with, or the DEK unwrapped from the token may not be the one it was encrypted with —
cipher.jacarta.key_label "komrad-backup-key" may no longer name the key this backup was
wrapped to (key rotation, a re-imported key, or a second GOST key on the same token all
select a valid-looking but wrong key). ...

У этой ошибки две неразличимые причины:

  1. Архив действительно повреждён или подменён.
  2. cipher.jacarta.key_label больше не указывает на тот ключ, которым была зашифрована копия — при полностью целом архиве.

Второе возможно потому, что обёртка DEK не аутентифицирована. openssl pkeyutl -derive успешно выводит KEK и на «не том» ключе (результат проверяется только по длине), а снятие обёртки «Кузнечиком» в режиме CFB собственной проверки целостности не имеет. Токен возвращает корректный по формату 32-байтный DEK без единой ошибки, и первым и единственным симптомом становится несовпадение имитовставки.

Типичные причины расхождения метки:

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

Отдельный случай — копия, созданная без key_label: манифест хранит метку в необязательном поле, поэтому при восстановлении токену передаётся пустая метка и он может вернуть ключ, к которому копия никогда не привязывалась. Сообщение об ошибке в этом случае прямо указывает, что метка в манифесте не записана.

warning

Повторный запуск той же команды restore ничего не изменит. Штатный потоковый путь прекращает подбор DEK сразу после успешного ответа токена и к escrow не переходит, поэтому неизменённый повтор воспроизведёт то же несовпадение байт в байт.

Что делать

Сообщение об ошибке само называет применимый способ восстановления — их три, и выбор зависит от того, есть ли в архиве escrow-копия DEK и известна ли escrow-фраза на этом узле.

Хвост сообщенияСостояниеДействие
carries an escrow copy of the DEK and an escrow passphrase is configured hereEscrow-блок в архиве есть, фраза задана на этом узлеЗадайте cipher.jacarta.verify_before_write: true и повторите восстановление — escrow-DEK будет проверен по тем же байтам шифртекста
carries an escrow copy of the DEK but no escrow passphrase is configured hereEscrow-блок есть, фразы на этом узле нетЗадайте cipher.escrow.passphrase (или передайте --passphrase) вместе с verify_before_write: true и повторите восстановление
carries no escrow copy of the DEKПри создании копии escrow-фраза не задаваласьEscrow-восстановление для этого архива недоступно. Единственный путь — подключить токен с тем самым ключом: проверьте key_label и наличие исходного ключа на токене

Если DEK был получен не от токена, а из escrow, сообщение будет другим: метка ключа в нём не фигурирует, а называется вторая пара причин — повреждение архива либо неверная escrow-фраза. Снятие escrow-обёртки так же не аутентифицировано, поэтому неверная фраза даёт неверный DEK без собственной ошибки.

Наконец, сообщение jacarta: token HMAC compute: ...; cannot verify stream (режим проверки перед записью) означает, что целостность потока не проверялась вовсе: сбой произошёл при локальном вычислении имитовставки — например, на узле нет ГОСТ-движка OpenSSL. Это проблема окружения узла, а не архива.

Безопасность

  • PIN токена не появляется в argv процессов: сайдкар получает его через KOMRAD_JACARTA_PIN, OpenSSL — через pin-source=file: (временный файл с правами 0600).
  • Симметричные ключи не передаются через argv. «Кузнечик» и HMAC-Стрибог-256 выполняются внутри процесса komrad-cli, ключи существуют только как области памяти. Ключ и IV не передаются дочернему openssl enc через -K/-iv/-macopt, где были бы видны в /proc/<pid>/cmdline любому локальному пользователю; запрет закреплён регрессионным тестом по всему пакету шифрования.
  • В argv дочерних процессов openssl остаются только несекретные значения: UKM схемы VKO (ukmhex: — случайный несекретный нонс), идентификатор параметров кривой (paramset:) и пути к файлам. Сайдкару передаются только --module, --token-label и --key-label.
  • Остаточная поверхность — эфемерный закрытый ключ. При создании копии эфемерная ключевая пара ГОСТ записывается во временный файл с правами 0600 (он нужен openssl pkeyutl -derive) и удаляется сразу после вывода KEK. Файл живёт доли секунды и относится лишь к одному блобу, но на это время доступен учётной записи, от имени которой выполняется backup create. Запускайте backup create от выделенной учётной записи и не размещайте TMPDIR в общедоступном каталоге.
  • Все переменные ${ИМЯ}, упомянутые в конфиге, вычищаются из окружения дочерних процессов.
  • Манифест не шифруется и не содержит секретов.