ЭЦП - что там под капотом

  • Михаил
  • 8 мин. на прочтение
  • 7
  • 24 Apr 2026
  • 24 Apr 2026

Давайте разберём по полочкам, что такое электронная подпись, какие бывают форматы, как они устроены внутри и почему в российской практике (ГОСТ, КриптоПро, ЭДО) возникают специфические требования.


🔐 1. Что такое электронная подпись (ЭП) на уровне криптографии

Это не картинка с росчерком. Это математическая конструкция, которая гарантирует:

Гарантия

Как достигается

Целостность

Данные хешируются. Любое изменение меняет хеш → подпись не совпадает

Авторство

Хеш шифруется приватным ключом владельца. Расшифровать можно только публичным ключом из сертификата

Неотказуемость

Приватный ключ хранится только у владельца (токен/Смарт-карта). Доказать подлинность можно в суде

Схема работы:

Данные → [Хеш-функция ГОСТ Р 34.11-2012] → Хеш → [Шифрование ГОСТ Р 34.10-2012 приватным ключом] → Подпись

Подпись + Публичный ключ → [Расшифровка] → Полученный хеш ↔ [Вычисление хеша из данных] → Совпадают? → ✅ Подпись верна


📦 2. Отсоединённая vs Присоединённая подпись

 

Параметр

Отсоединённая (Detached)

Присоединённая (Attached/Enveloped)

Структура

Данные и подпись хранятся в разных файлах

Данные и подпись упакованы в один файл

Примеры

contract.pdf + contract.pdf.p7s

contract.pdf.p7m или PDF со встроенной ЭП

Читаемость данных

✅ Данные можно открыть без валидатора

❌ Данные "зашифрованы" внутри контейнера (на самом деле просто упакованы)

Размер

Подпись отдельно (~1–4 КБ)

Файл увеличивается на размер подписи + сертификатов

Где используется

ЭДО (СБИС, Контур, Диадок), гос. порталы, API, ФНС

Архивирование, почта (S/MIME), некоторые корп. системы

Требования РФ

🔥 Стандарт де-факто для УКЭП по 63-ФЗ

Реже, в основном для S/MIME или специфичных систем

💡 Почему в России почти всегда используют отсоединённую?
Потому что данные должны оставаться в исходном формате (PDF, XML, JSON), а подпись прикладывается как юридический "штемпель". Так работают все аккредитованные операторы ЭДО и гос. сервисы.

📜 3. Форматы файлов и стандарты

 

Формат

Расширение

Описание

Совместимость с ГОСТ/КриптоПро

CMS / PKCS#7

.p7s, .p7m, .p7c

Бинарный контейнер ASN.1 (DER). .p7s = detached, .p7m = attached

✅ Полная. Основа для 90% ЭП в РФ

CAdES

.p7s, .sig

Профиль CMS с атрибутами долгосрочной валидности (LTV). Добавляет signingTime, messageDigest, OCSP, метки времени

✅ Требуется в гос. системах, ФНС, крупных ЭДО

XML-DSig

.xml

Подпись встроена в XML-документ

⚠️ Используется в ФНС, ЕГРЮЛ, но не для бинарных данных

PAdES

.pdf

Встроенная подпись в PDF (стандарт ETSI)

✅ Поддерживается КриптоПро, Adobe, но требует специфичных библиотек

Base64 + JSON

.json

Нестандартный, но популярный в веб-API: {"signature":"...","cert":"..."}

❌ Только если принимающая система явно разрешает

📌 Важно: .p7s и .sig часто означают одно и то же (CMS detached). Разница лишь в договорённостях оператора ЭДО или вендора.

🔍 4. Как выглядит подпись "под капотом" (структура CMS)

CMS/PKCS#7 кодируется в ASN.1 → DER (бинарный формат). Его нельзя читать текстовым редактором. Упрощённая структура:

ContentInfo
 └─ SignedData
    ├─ digestAlgorithms       : [OID хеша, например 1.2.643.7.1.1.2.2]
    ├─ encapContentInfo       : { eContentType: data, eContent: NULL } ← NULL = detached
    ├─ certificates           : [X509Certificate в DER]
    ├─ crls                   : [] (опционально)
    └─ signerInfos
       ├─ signerIdentifier    : IssuerDN + SerialNumber
       ├─ digestAlgorithm     : OID хеша
       ├─ signedAttributes    : [опционально: signingTime, messageDigest, contentType]
       ├─ signatureAlgorithm  : OID подписи
       └─ signature           : OCTET STRING → для ГОСТ это сырые байты r||s (64 байта)

 

🔑 Критичный момент для ГОСТ:

В стандарте RFC 4490 (GOST CMS) поле signature содержит сырую конкатенацию r || s, а НЕ ASN.1-обёртку SEQUENCE { r, s }.
Именно из-за этого КриптоПро выдает популярную ошибку 0x80090006, когда вы передаете DER-кодированную подпись.


🇷🇺 5. Российская специфика (ГОСТ, КриптоПро, СКЗИ)

 

Требование

Описание

Алгоритмы

ГОСТ Р 34.10-2012 (256/512 бит) + ГОСТ Р 34.11-2012

Сертификат

УКЭП, выданный аккредитованным УЦ Минцифры

Формат

CMS detached (.p7s или .sig), кодировка DER

Атрибуты

Многие валидаторы требуют signedAttributes с messageDigest (хеш данных), даже для detached. Без него → 0x80090006

Параметры алгоритмов

В AlgorithmIdentifier часто допустим NULL, но некоторые сборки КриптоПро требуют явный OID набора параметров

Проверка

cryptcp -verify -detached -sign doc.p7s -data doc.json -cert cert.cer

⚠️ Почему КриптоПро может ругаться на "неправильную подпись", хотя математически всё верно?
Потому что валидатор проверяет не только криптографию, но и соответствие профилям: наличие атрибутов, порядок полей, отсутствие лишних байтов, правильные OID. Это "юридическая" валидация, а не только математическая.

📂 6. Как выглядят файлы на практике

✅ Отсоединённая .p7s

 

document.json       (1.2 КБ, читаемый текст)
document.json.p7s   (3.4 КБ, бинарный DER)

Проверка: берётся document.json → вычисляется хеш → сравнивается с хешом, зашифрованным в .p7s.

✅ Присоединённая .p7m

 

document.pdf.p7m    (1.5 МБ, внутри: PDF + сертификат + подпись)

Проверка: распаковывается → извлекаются данные → проверяется подпись.

🌐 Base64-обёртка (иногда требуется)

Некоторые системы ожидают не бинарный DER, а PEM-подобный формат:

-----BEGIN CMS-----
MIIGZQYJKoZIhvcNAQcCoIIGVjCCBlICAQExDTAL...
-----END CMS-----

Получается просто: Convert.ToBase64String(p7sBytes) + заголовки.


7. Что выбирать разработчику? Чек-лист

 

Задача

Рекомендуемый формат

Отправка в СБИС, Контур, ФНС, ЭДО

CMS detached (.p7s) + сертификат внутри

Веб-сервис / REST API

JSON {"signature":"base64","cert":"base64","algorithm":"GOST..."} (если разрешено)

Долгосрочное архивирование (5+ лет)

CAdES-T или CAdES-A (с меткой времени и OCSP)

Документы для печати/хранения

PDF с PAdES

Внутренняя система без требований СКЗИ

Любой валидируемый формат, но лучше CMS

🔍 Обязательно уточняйте у принимающей стороны:

  1. Формат: .p7s, .sig, PEM или raw base64?
  2. Требуется ли signedAttributes (messageDigest, signingTime)?
  3. Нужен ли CAdES-BES/T или достаточно базового CMS?
  4. Должен ли сертификат быть встроен в .p7s или передаётся отдельно?
  5. Допустимы ли "сырые" подписи без ASN.1-обёртки? (для ГОСТ → да, но валидатор должен это поддерживать)

8. Как отлаживать и проверять

 

Инструмент

Команда / Действие

Просмотр структуры

openssl cms -in file.p7s -inform DER -text -noout

Проверка КриптоПро

cryptcp -verify -detached -sign file.p7s -data data.bin -cert cert.cer

csptest.exe -sfsign -verify -detached -in document.json -signature document.json.sig -my "Сертификат"

Проверка OpenSSL (GOST)

openssl cms -verify -in file.p7s -inform DER -content data.bin -CAfile cert.cer -noverify

Онлайн-валидаторы

Контур.Крипто, КриптоПро DSS, ФНС-сервисы

Парсинг байтов

Откройте .p7s в Hex-редакторе. Первые байты: 30 82 → начало DER-контейнера


📌 Итог

  • Отсоединённая подпись = данные отдельно, подпись отдельно. Стандарт для РФ.
  • Формат = CMS/PKCS#7 в DER (.p7s), иногда CAdES для LTV.
  • Для ГОСТ подпись внутри CMS хранится как r||s (сырые байты), а не DER-последовательность.
  • КриптоПро проверяет не только математику, но и соответствие профилям: атрибуты, OID, порядок полей.
  • Всегда сверяйтесь с требованиями принимающей системы. "Рабочая" подпись в одной системе может быть "неправильной" в другой из-за политик валидации.