Chat
Ask me anything
Ithy Logo

Раскрываем Секреты: Создание Отсоединенной Подписи CAdES-BES с ГОСТ Р в Python – Ваш Полный Гид!

Пошаговое руководство по генерации безопасных электронных подписей российского стандарта для ваших файлов с использованием Python.

cades-bes-gost-r-python-signature-2i16doz0

Основные моменты

  • Отсоединенная подпись CAdES-BES: Позволяет подписывать данные, сохраняя подпись отдельно от самого файла, что идеально для верификации без необходимости встраивания исходных данных в файл подписи.
  • Алгоритмы ГОСТ Р: Использование российских криптографических стандартов ГОСТ Р 34.10-2012 (для создания электронной подписи) и ГОСТ Р 34.11-2012 (для хеширования) обеспечивает соответствие нормативным требованиям и высокий уровень безопасности.
  • Реализация на Python: Представлен практический пример кода с использованием библиотек gostcrypto и asn1crypto для формирования структуры подписи CAdES-BES в соответствии со стандартами.

Введение: Зачем нужна отсоединенная подпись CAdES-BES ГОСТ Р?

В современном цифровом мире обеспечение подлинности и целостности электронных документов имеет первостепенное значение. Электронные подписи (ЭП) служат этой цели, предоставляя криптографические гарантии. CAdES (CMS Advanced Electronic Signatures) – это набор стандартов для расширенных электронных подписей, построенных на основе CMS (Cryptographic Message Syntax). CAdES-BES (Basic Electronic Signature) является базовым форматом, который подтверждает, что подпись была создана конкретным подписантом.

Отсоединенная подпись (detached signature) означает, что сама подпись хранится отдельно от подписываемых данных. Это особенно удобно, когда исходный файл велик или когда его нежелательно изменять. Использование алгоритмов ГОСТ Р (Государственный Стандарт Российской Федерации) обеспечивает соответствие российскому законодательству и криптографическим требованиям.

Это руководство покажет, как создать отсоединенную подпись CAdES-BES с использованием алгоритмов ГОСТ Р в Python, что позволит вам интегрировать надежные механизмы ЭП в ваши приложения.

Процесс создания и упаковки цифровой подписи

Иллюстрация процесса создания и упаковки цифровой подписи.


Ключевые компоненты и стандарты

Для создания подписи CAdES-BES ГОСТ Р необходимо понимать основные стандарты и компоненты, участвующие в процессе.

Алгоритмы ГОСТ Р: Основа российской криптографии

Российские стандарты ГОСТ Р играют ключевую роль в обеспечении криптографической защиты информации.

ГОСТ Р 34.10-2012: Стандарт электронной подписи

Этот стандарт определяет алгоритмы формирования и проверки электронной подписи на основе эллиптических кривых. Он пришел на смену ГОСТ Р 34.10-2001 и предлагает повышенный уровень безопасности. Для подписей CAdES-BES мы будем использовать именно этот стандарт.

ГОСТ Р 34.11-2012: Стандарт хеширования

Данный стандарт определяет алгоритм хеш-функции ("Стрибог"), используемый для вычисления хеш-значения (дайджеста) подписываемых данных. Дайджест затем подписывается с использованием ГОСТ Р 34.10-2012. Стандарт предусматривает два варианта длины хеш-значения: 256 бит и 512 бит.

CAdES-BES: Базовый формат улучшенной электронной подписи

CAdES-BES (CMS Advanced Electronic Signatures - Basic Electronic Signature) – это базовый уровень формата CAdES, определенный в ETSI TS 101 733. Он обеспечивает подтверждение того, что подпись была создана, и связывает ее с подписанными данными через хеш.

Структура SignedData

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

SignedAttributes: Гарантия целостности контекста

Подписываемые атрибуты (SignedAttributes) являются критически важной частью CAdES. Они подписываются вместе с хешем документа и включают как минимум:

  • content-type: Идентификатор типа подписываемых данных.
  • message-digest: Хеш-значение подписываемых данных.
  • signing-time: Время создания подписи (необязательный, но рекомендуемый атрибут для BES).

Подписание этих атрибутов защищает от некоторых видов атак, например, от подмены самого хеша.

Отсоединенная подпись: Гибкость и эффективность

При использовании отсоединенной подписи, файл подписи (часто с расширением .sig или .p7s) создается отдельно от исходного документа. Это позволяет:

  • Хранить и передавать документ и подпись независимо.
  • Подписывать очень большие файлы без необходимости включать их содержимое в структуру подписи.
  • Применять несколько подписей к одному документу без изменения самого документа.
Сертификация ГОСТ Р

Сертификация ГОСТ Р как символ соответствия российским стандартам криптографии.


Практическая реализация: Подписываем файл в Python

Для создания отсоединенной подписи CAdES-BES с ГОСТ Р в Python мы воспользуемся комбинацией библиотек: gostcrypto для криптографических операций ГОСТ и asn1crypto для формирования ASN.1 структур, необходимых для CAdES/CMS.

Необходимые инструменты: Библиотеки Python

Убедитесь, что у вас установлены следующие библиотеки:

pip install gostcrypto asn1crypto
  • gostcrypto: Предоставляет реализации российских криптографических алгоритмов, включая ГОСТ Р 34.10-2012 и ГОСТ Р 34.11-2012.
  • asn1crypto: Мощная библиотека для работы с ASN.1 структурами, которая поможет нам построить формат CAdES-BES.

Пошаговый процесс создания подписи

  1. Импорт библиотек и подготовка данных: Подключаем необходимые модули.
  2. Загрузка исходного файла, закрытого ключа ГОСТ и сертификата: Для создания подписи необходим закрытый ключ стандарта ГОСТ Р 34.10-2012 и соответствующий ему сертификат открытого ключа.
  3. Вычисление хеш-суммы файла: Используем ГОСТ Р 34.11-2012 (например, 256-битную версию) для получения дайджеста подписываемого файла.
  4. Формирование подписываемых атрибутов (SignedAttributes): Создаем структуру, включающую тип контента, дайджест сообщения и время подписи.
  5. Хеширование SignedAttributes: Получаем хеш-сумму сериализованных подписываемых атрибутов, также используя ГОСТ Р 34.11-2012.
  6. Создание цифровой подписи: Подписываем хеш атрибутов закрытым ключом ГОСТ Р 34.10-2012.
  7. Формирование объекта SignerInfo: Этот объект содержит информацию о подписанте, использованных алгоритмах, подписываемых атрибутах и самой подписи.
  8. Сборка структуры SignedData: Основная структура CMS, содержащая SignerInfo и другую метаинформацию. Для отсоединенной подписи исходные данные не включаются.
  9. Обертывание в ContentInfo и сохранение подписи: Финальная структура, готовая для сохранения в файл (обычно с расширением .p7s или .sig).

Фрагмент кода Python


from datetime import datetime, timezone
import gostcrypto.gostsignature as gostsig
import gostcrypto.gosthash as gosthash
from gostcrypto import encoding # Может понадобиться для специфических кодировок ключей

from asn1crypto import cms, core, x509, algos, pem

# --- Параметры ---
FILE_TO_SIGN_PATH = 'document.txt'  # Путь к подписываемому файлу
PRIVATE_KEY_PATH = 'private_key.pem' # Путь к файлу закрытого ключа ГОСТ (PEM формат)
CERTIFICATE_PATH = 'certificate.cer' # Путь к файлу сертификата ГОСТ (DER или PEM формат)
SIGNATURE_OUTPUT_PATH = 'document.txt.p7s' # Путь для сохранения файла отсоединенной подписи

# --- 1. Загрузка данных и ключей/сертификатов ---
try:
    # Чтение файла для подписи
    with open(FILE_TO_SIGN_PATH, 'rb') as f:
        data_to_sign = f.read()

    # Загрузка закрытого ключа ГОСТ Р 34.10-2012
    # gostcrypto ожидает ключ в бинарном формате (DER) или специальном PEM с GOST параметрами
    # Если ключ в PEM, его нужно предварительно обработать или убедиться, что gostcrypto его понимает
    # Для примера, предположим, что ключ уже в подходящем формате или gostcrypto.load_private_key это обработает.
    with open(PRIVATE_KEY_PATH, 'rb') as f:
        private_key_pem_data = f.read()
    
    # Пытаемся определить, PEM ли это, и извлечь DER-содержимое, если необходимо для gostcrypto
    # gostcrypto.load_private_key может ожидать DER-байт или специфичный PEM.
    # Этот шаг может потребовать адаптации в зависимости от формата вашего ключа.
    # В данном примере мы предполагаем, что load_private_key справится с PEM или вы предоставите DER.
    # Для простоты, если это PEM, используем encoding.pem_armor_decode, если он есть
    try:
        # Пробуем декодировать PEM, если это он
        _, _, private_key_der_data = pem.unarmor(private_key_pem_data)
    except ValueError:
        # Если не PEM, считаем, что это DER
        private_key_der_data = private_key_pem_data
        
    private_key = gostsig.load_private_key(private_key_der_data) # Пароль, если ключ зашифрован

    # Загрузка сертификата подписанта (для SignerIdentifier и включения в подпись)
    with open(CERTIFICATE_PATH, 'rb') as f:
        cert_data = f.read()
    
    # asn1crypto.x509.Certificate.load может загружать PEM или DER автоматически
    certificate = x509.Certificate.load(cert_data)

except FileNotFoundError as e:
    print(f"Ошибка: Файл не найден - {e.filename}")
    exit()
except Exception as e:
    print(f"Ошибка при загрузке ключей/сертификата: {e}")
    exit()

# --- 2. Вычисление хеша файла (ГОСТ Р 34.11-2012, 256 бит) ---
data_digest = gosthash.new('streebog256', data_to_sign).digest()

# --- 3. Формирование SignedAttributes ---
# Обязательные атрибуты для CAdES-BES: content-type, message-digest. signing-time рекомендуется.
signed_attrs = cms.CMSAttributes([
    cms.CMSAttribute({
        'type': cms.CMSAttributeType('content_type'),
        'values': [cms.ContentType('data')] # OID for id-data: 1.2.840.113549.1.7.1
    }),
    cms.CMSAttribute({
        'type': cms.CMSAttributeType('message_digest'),
        'values': [data_digest]
    }),
    cms.CMSAttribute({
        'type': cms.CMSAttributeType('signing_time'),
        # Время должно быть в UTC и формате UTCTime или GeneralizedTime
        'values': [core.UTCTime(datetime.now(timezone.utc))]
    }),
    # Можно добавить другие атрибуты, например, signing_certificate_v2 (ETSI TS 101 733 / RFC 5035)
    # Для CAdES-BES часто ожидается ETSI-defined SigningCertificateV2 attribute
    # cms.CMSAttribute({
    #     'type': cms.CMSAttributeType('1.2.840.113549.1.9.16.2.47'), # id-aa-signingCertificateV2
    #     'values': [...] # Требует структуры ESSCertIDv2
    # })
])

# Сериализация SignedAttributes (в DER формате, SET OF) для последующего хеширования
# Важно: атрибуты должны быть закодированы как SET OF для хеширования
signed_attrs_der = signed_attrs.dump()

# --- 4. Хеширование SignedAttributes (ГОСТ Р 34.11-2012, 256 бит) ---
signed_attrs_hash = gosthash.new('streebog256', signed_attrs_der).digest()

# --- 5. Создание подписи хеша атрибутов (ГОСТ Р 34.10-2012) ---
# gostsig.sign подписывает переданные байты (в нашем случае хеш атрибутов)
raw_signature = gostsig.sign(private_key, signed_attrs_hash)

# --- 6. Формирование SignerInfo ---
signer_info = cms.SignerInfo({
    'version': 'v1', # Версия в зависимости от типа sid (issuerAndSerialNumber -> v1, subjectKeyIdentifier -> v3)
    'sid': cms.SignerIdentifier({
        'issuer_and_serial_number': cms.IssuerAndSerialNumber({
            'issuer': certificate.issuer,
            'serial_number': certificate.serial_number
        })
    }),
    'digest_algorithm': algos.DigestAlgorithm({'algorithm': '1.2.643.7.1.1.2.2'}), # OID ГОСТ Р 34.11-2012 (256) - Streebog256
    'signed_attrs': signed_attrs, # Включаем сами атрибуты
    'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': '1.2.643.7.1.1.1.1'}), # OID ГОСТ Р 34.10-2012 (256)
    'signature': raw_signature,
    # 'unsigned_attrs': опционально
})

# --- 7. Сборка SignedData ---
# Для отсоединенной подписи, encap_content_info.content не указывается
signed_data = cms.SignedData({
    'version': 'v1', # или v3, v4, v5 в зависимости от используемых фич
    'digest_algorithms': [algos.DigestAlgorithm({'algorithm': '1.2.643.7.1.1.2.2'})], # Алгоритмы хеширования, используемые подписантами
    'encap_content_info': cms.EncapsulatedContentInfo({
        'content_type': cms.ContentType('data'), # Тип исходных данных
        # 'content': data_to_sign # НЕ включаем для отсоединенной подписи
    }),
    'certificates': [certificate], # Включаем сертификат подписанта
    # 'crls': [], # Можно включить CRL
    'signer_infos': [signer_info]
})

# --- 8. Обертывание в ContentInfo и сохранение ---
content_info = cms.ContentInfo({
    'content_type': cms.ContentType('signed_data'), # OID for id-signedData: 1.2.840.113549.1.7.2
    'content': signed_data
})

# Сохранение отсоединенной подписи в файл
with open(SIGNATURE_OUTPUT_PATH, 'wb') as f:
    f.write(content_info.dump()) # Сериализация в DER формат

print(f"Отсоединенная подпись CAdES-BES ГОСТ Р успешно создана и сохранена в: {SIGNATURE_OUTPUT_PATH}")

    

Разбор кода: Что происходит "под капотом"?

  • Загрузка данных: Читается файл, который необходимо подписать, а также закрытый ключ и сертификат подписанта. Формат ключа и сертификата должен быть совместим с используемыми библиотеками. gostcrypto обычно работает с ключами в формате DER или специфическом PEM для ГОСТ. asn1crypto может парсить сертификаты в DER или PEM формате.
  • Хеширование файла: С помощью gosthash.new('streebog256', data_to_sign).digest() вычисляется дайджест (хеш) содержимого файла по алгоритму ГОСТ Р 34.11-2012 (256-битная версия "Стрибог").
  • Формирование SignedAttributes: Создается ASN.1 структура cms.CMSAttributes, содержащая обязательные для CAdES-BES атрибуты: тип контента (content_type), дайджест сообщения (message_digest), и время подписи (signing_time). Эти атрибуты сериализуются в DER-формат (signed_attrs.dump()), так как именно эта бинарная строка будет хешироваться и подписываться.
  • Хеширование SignedAttributes: Сериализованные атрибуты хешируются тем же алгоритмом ГОСТ Р 34.11-2012.
  • Создание подписи: Функция gostsig.sign(private_key, signed_attrs_hash) использует загруженный закрытый ключ ГОСТ Р 34.10-2012 для подписи хеша атрибутов.
  • Формирование SignerInfo: Это ключевая структура, описывающая одного подписанта. Она включает:
    • sid (Signer Identifier): Идентификатор подписанта, обычно через издателя и серийный номер сертификата (IssuerAndSerialNumber).
    • digest_algorithm: OID алгоритма хеширования, использованного для SignedAttributes (в нашем случае, ГОСТ Р 34.11-2012).
    • signed_attrs: Сами подписываемые атрибуты.
    • signature_algorithm: OID алгоритма подписи (ГОСТ Р 34.10-2012).
    • signature: Непосредственно цифровая подпись (байты).
  • Сборка SignedData: Эта структура "обертывает" всю информацию о подписи. Для отсоединенной подписи поле encap_content_info не содержит самих данных (content), а лишь указывает их тип (content_type: 'data'). В SignedData также включаются использованные алгоритмы хеширования, сертификат(ы) подписантов и массив структур SignerInfo.
  • Обертывание в ContentInfo и сохранение: SignedData упаковывается в финальную структуру ContentInfo, которая затем сериализуется в DER-формат (content_info.dump()) и сохраняется в файл. Этот файл и является отсоединенной электронной подписью.

Важно: Представленный код является примером. Реальная работа с криптографическими ключами и сертификатами требует строгого соблюдения мер безопасности, включая безопасное хранение ключей и управление жизненным циклом сертификатов. Также может потребоваться более сложная обработка ошибок и адаптация под конкретные форматы ключей/сертификатов.


Визуализация процесса: Схема создания подписи

Чтобы лучше понять последовательность шагов при создании отсоединенной подписи CAdES-BES с использованием алгоритмов ГОСТ Р, рассмотрим следующую ментальную карту. Она иллюстрирует ключевые этапы, начиная от подготовки данных и заканчивая формированием файла подписи.

mindmap root["Создание отсоединенной подписи CAdES-BES ГОСТ Р"] id1["Подготовка данных"] id1_1["Исходный файл (документ)"] id1_2["Закрытый ключ ГОСТ Р 34.10-2012"] id1_3["Сертификат открытого ключа ГОСТ"] id2["Хеширование данных файла"] id2_1["Алгоритм: ГОСТ Р 34.11-2012 (Стрибог)"] id2_2["Результат: Дайджест файла (Message Digest)"] id3["Формирование SignedAttributes (Подписываемые Атрибуты)"] id3_1["Content-Type (Тип контента)"] id3_2["Message-Digest (Дайджест файла)"] id3_3["Signing-Time (Время подписи)"] id3_4["(Опционально) SigningCertificateV2 и др."] id3_5["Сериализация атрибутов в DER (SET OF)"] id4["Подписание атрибутов"] id4_1["Хеширование сериализованных SignedAttributes (ГОСТ Р 34.11-2012)"] id4_2["Подпись хеша атрибутов ключом ГОСТ Р 34.10-2012"] id4_3["Результат: 'Сырая' подпись (Raw Signature)"] id5["Сборка структуры CMS/CAdES"] id5_1["SignerInfo (Информация о подписанте)"] id5_1_1["Версия"] id5_1_2["SID (Идентификатор подписанта: IssuerAndSerialNumber)"] id5_1_3["DigestAlgorithm (Алгоритм хеширования атрибутов)"] id5_1_4["SignedAttributes (Сами атрибуты)"] id5_1_5["SignatureAlgorithm (Алгоритм подписи)"] id5_1_6["Signature (Сырая подпись)"] id5_2["SignedData (Подписанные данные)"] id5_2_1["Версия"] id5_2_2["DigestAlgorithms (Список алгоритмов хеширования)"] id5_2_3["EncapContentInfo (Тип исходных данных, без самих данных для отсоединенной подписи)"] id5_2_4["Certificates (Сертификат(ы) подписанта)"] id5_2_5["CRLs (Опционально: Списки отозванных сертификатов)"] id5_2_6["SignerInfos (Список SignerInfo)"] id5_3["ContentInfo (Контейнер верхнего уровня)"] id5_3_1["ContentType (Тип: signedData)"] id5_3_2["Content (Сама структура SignedData)"] id6["Результат"] id6_1["Файл отсоединенной подписи (например, .p7s, .sig)"] id6_2["Сериализация ContentInfo в DER-формат"]

Эта схема наглядно демонстрирует все этапы, которые проходит система для генерации корректной отсоединенной подписи CAdES-BES ГОСТ Р.


Сравнение подходов: Обзор библиотек для Python

При реализации поддержки ГОСТ и CAdES в Python разработчики могут столкнуться с выбором между различными библиотеками и подходами. Диаграмма ниже представляет сравнительный анализ нескольких условных подходов по ключевым критериям. Оценки носят субъективный характер и призваны дать общее представление.

Как видно из диаграммы, подход с использованием gostcrypto и asn1crypto предлагает хороший баланс между соответствием стандартам ГОСТ, возможностью реализации CAdES и доступностью (бесплатные open-source библиотеки), хотя и требует более глубокого понимания структур ASN.1. Коммерческие решения, такие как Chilkat (если они поддерживают ГОСТ в вашей конфигурации), могут предложить большую простоту использования и полноту CAdES "из коробки", но ценой лицензионных отчислений.


Ключевые идентификаторы объектов (OID) в подписях ГОСТ CAdES-BES

Идентификаторы объектов (Object Identifiers, OID) играют фундаментальную роль в структурах ASN.1, таких как CMS/CAdES. Они однозначно определяют алгоритмы, типы данных, атрибуты и другие элементы. Ниже приведена таблица с некоторыми ключевыми OID, релевантными для создания подписей ГОСТ Р CAdES-BES.

OID Описание Мнемоника / Ссылка на стандарт
1.2.643.7.1.1.2.2 Алгоритм хеширования ГОСТ Р 34.11-2012 (256 бит, "Стрибог") id-tc26-gost3411-12-256
1.2.643.7.1.1.1.1 Алгоритм цифровой подписи ГОСТ Р 34.10-2012 (с 256-битными параметрами) id-tc26-gost3410-12-256
1.2.840.113549.1.7.1 Тип содержимого "data" (произвольные данные) id-data (PKCS#7/CMS)
1.2.840.113549.1.7.2 Тип содержимого "signedData" (подписанные данные CMS) id-signedData (PKCS#7/CMS)
1.2.840.113549.1.9.3 Атрибут "contentType" (тип содержимого) contentType (PKCS#9 / CMS)
1.2.840.113549.1.9.4 Атрибут "messageDigest" (дайджест сообщения) messageDigest (PKCS#9 / CMS)
1.2.840.113549.1.9.5 Атрибут "signingTime" (время подписи) signingTime (PKCS#9 / CMS)
1.2.840.113549.1.9.16.2.47 Атрибут "id-aa-signingCertificateV2" (рекомендован для CAdES) ETSI TS 101 733 / RFC 5035

Знание этих OID помогает при отладке и анализе структур электронных подписей, а также при работе с низкоуровневыми криптографическими библиотеками.


Важные аспекты и рекомендации

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

Управление ключами и сертификатами

Закрытые ключи должны храниться в строгой тайне и с использованием защищенных механизмов (например, аппаратные токены PKCS#11, защищенные хранилища ОС). Компрометация закрытого ключа ведет к возможности подделки подписей от имени владельца. Сертификаты открытых ключей должны быть выданы доверенными удостоверяющими центрами (УЦ) и своевременно обновляться.

Обработка ошибок и исключений

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

Совместимость и версии библиотек

Убедитесь, что версии используемых библиотек (gostcrypto, asn1crypto и их зависимостей, таких как OpenSSL) совместимы между собой и поддерживают необходимые алгоритмы ГОСТ. Иногда для поддержки ГОСТ на уровне системы может потребоваться специальная сборка OpenSSL.

Проверка (валидация) созданной подписи

После создания подписи рекомендуется проводить ее проверку с использованием эталонных инструментов или сервисов валидации (например, сервисы УЦ, тестовые площадки государственных порталов, если они поддерживают CAdES-BES ГОСТ Р). Это поможет убедиться в корректности сформированной подписи и ее соответствии стандартам.

Обзор профилей цифровых подписей eIDAS

Обзор различных профилей цифровых подписей, включая CAdES, в контексте европейского регламента eIDAS. Подобные профили существуют и для российских стандартов.


Часто задаваемые вопросы (FAQ)

Что такое отсоединенная подпись и в чем ее преимущество?
Какие версии ГОСТ Р используются для подписи CAdES-BES?
Обязательно ли использовать asn1crypto вместе с gostcrypto?
Где взять закрытый ключ и сертификат ГОСТ?
Как проверить правильность созданной подписи?

Рекомендуемые запросы для дальнейшего изучения


Источники


Last updated May 12, 2025
Ask Ithy AI
Download Article
Delete Article