Встроенные криптографические примитивы: subtle crypto под капотом

В библиотеке jose криптографические операции не реализуются вручную: они делегируются встроенному в среду выполнения механизму Web Crypto API, а именно интерфейсу SubtleCrypto. Это ключевой слой, через который происходят все операции подписи, проверки, шифрования и управления ключами. Архитектура построена так, чтобы исключить прямую работу с «сырыми» криптографическими алгоритмами и минимизировать вероятность ошибок, связанных с безопасностью.

Web Crypto API предоставляет объект crypto.subtle, который является интерфейсом к нативной криптографической подсистеме браузера или Node.js (через WebCrypto-полифил или встроенную реализацию).

Основная идея SubtleCrypto заключается в том, что криптографические операции выполняются вне JavaScript-рантайма, на уровне платформы:

  • операции выполняются асинхронно;
  • ключи не извлекаются в виде «сырого» материала без необходимости;
  • большинство алгоритмов имеют строгие ограничения по использованию;
  • доступ к приватным ключам ограничен политиками экспорта.

Jose полностью опирается на этот слой, не реализуя криптографию самостоятельно.

Архитектура jose и делегирование криптографии

Библиотека jose строится вокруг стандарта JOSE (JSON Object Signing and Encryption), включающего:

  • JWS (JSON Web Signature)
  • JWE (JSON Web Encryption)
  • JWK (JSON Web Key)
  • JWA (JSON Web Algorithms)

Каждый из этих компонентов использует SubtleCrypto как исполнительный механизм.

При вызове, например, подписи JWT, jose не выполняет математические операции самостоятельно. Вместо этого происходит трансляция параметров JOSE в формат Web Crypto API:

  • алгоритм JOSE → алгоритм SubtleCrypto
  • JWK → CryptoKey
  • операции encode/decode → ArrayBuffer

Ключи: JWK и CryptoKey

В jose ключи часто представлены в формате JWK (JSON Web Key). Однако SubtleCrypto работает с объектами CryptoKey. Поэтому важным этапом является импорт и экспорт ключей.

Процесс импорта:

  • JWK передаётся в crypto.subtle.importKey
  • задаётся алгоритм (например, RS256, ES256)
  • указывается назначение ключа: sign, verify, encrypt, decrypt

Внутри SubtleCrypto ключ становится непрозрачным объектом. Его содержимое недоступно напрямую, что снижает риск утечки секретов через JavaScript-уровень.

Экспорт возможен только при явном разрешении (extractable: true), что используется редко в продакшн-криптографии.

Подпись данных: JWS через SubtleCrypto

Подписание в jose проходит через цепочку:

  1. формирование protected header (base64url)
  2. формирование payload
  3. конкатенация данных: header.payload
  4. передача в SubtleCrypto для подписи

Для алгоритмов RSA-PSS или ECDSA происходит вызов:

  • crypto.subtle.sign(algorithm, privateKey, data)

SubtleCrypto возвращает бинарную подпись, которая затем кодируется в base64url.

Для проверки подписи:

  • crypto.subtle.verify(algorithm, publicKey, signature, data)

Jose лишь координирует этот процесс, не вмешиваясь в криптографическую часть.

Шифрование и JWE: роль SubtleCrypto

В JWE процесс значительно сложнее, так как включает гибридную криптографию:

  • симметричный ключ для шифрования данных (content encryption key, CEK)
  • асимметричное шифрование CEK (например, RSA-OAEP)
  • симметричное шифрование payload (AES-GCM или AES-CBC + HMAC)

SubtleCrypto используется для всех этапов:

  • crypto.subtle.encrypt() для симметричного шифрования
  • crypto.subtle.decrypt() для обратной операции
  • crypto.subtle.wrapKey() и unwrapKey() для работы с CEK

Особенно важно, что AES-GCM реализуется нативно, включая аутентификационные теги, что исключает необходимость ручной реализации MAC.

Алгоритмическая модель JWA и маппинг на SubtleCrypto

JOSE определяет набор алгоритмов, каждый из которых имеет соответствие в Web Crypto API.

RSA:

  • RS256 → RSA-SHA256 (RSASSA-PKCS1-v1_5)
  • PS256 → RSA-PSS + SHA-256
  • RSA-OAEP → encryption key wrapping

ECC:

  • ES256 → ECDSA P-256 + SHA-256
  • ES384 → P-384
  • ES512 → P-521

Symmetric:

  • HS256 → HMAC SHA-256
  • A128GCM / A256GCM → AES-GCM

SubtleCrypto требует явного указания параметров:

  • name алгоритма
  • hash функция
  • длина ключа

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

Форматы данных: ArrayBuffer и base64url

SubtleCrypto работает с бинарными данными в формате ArrayBuffer. Однако JOSE использует текстовый формат JSON и base64url.

Поэтому jose включает слой преобразований:

  • UTF-8 → ArrayBuffer (TextEncoder)
  • ArrayBuffer → base64url
  • base64url → ArrayBuffer (decode)
  • ArrayBuffer → UTF-8 (TextDecoder)

Этот слой критичен, так как любая ошибка кодирования приводит к невозможности проверки подписи или расшифровки.

Асинхронная модель выполнения

Все операции SubtleCrypto являются асинхронными и возвращают Promise. Это связано с тем, что криптография выполняется вне основного потока JavaScript.

Jose строит API поверх этой модели:

  • await sign()
  • await verify()
  • await encrypt()
  • await decrypt()

Это позволяет избежать блокировки event loop при больших payload или сложных ключах RSA/ECC.

Безопасность SubtleCrypto и ограничения

SubtleCrypto накладывает ряд ограничений, которые напрямую влияют на поведение jose:

  • невозможность извлечения приватного ключа без разрешения
  • запрет на использование некоторых слабых алгоритмов
  • строгая типизация входных данных
  • зависимость от реализации платформы (браузер / Node.js)

Также важно, что криптографические операции выполняются в изолированной среде, что снижает риск утечек через side-channel на уровне JavaScript.

Особенности реализации в Node.js

В Node.js SubtleCrypto предоставляется через встроенный модуль crypto.webcrypto. Jose использует его автоматически при наличии.

Особенности:

  • поведение близко к браузерному
  • различия в поддержке алгоритмов минимальны
  • производительность выше за счёт нативной реализации OpenSSL

Однако возможны различия в доступности некоторых кривых ECC или режимов AES, что учитывается в jose через fallback-механизмы.

Абстракция jose над SubtleCrypto

Jose фактически выступает как адаптер между стандартом JOSE и Web Crypto API:

  • унифицирует различия браузеров и Node.js
  • скрывает работу с ArrayBuffer
  • автоматически подбирает алгоритмы
  • управляет форматами ключей

SubtleCrypto остаётся единственным криптографическим движком, а jose — слоем оркестрации и стандартизации.

Поток выполнения криптографических операций

Типичный поток внутри jose выглядит следующим образом:

  1. Парсинг JWT/JWE структуры
  2. Декодирование base64url сегментов
  3. Преобразование ключей JWK → CryptoKey
  4. Вызов SubtleCrypto операции
  5. Получение бинарного результата
  6. Кодирование результата обратно в JOSE формат

Каждый этап строго детерминирован и не содержит скрытой логики вне Web Crypto API.

Практическая значимость SubtleCrypto в архитектуре jose

Использование SubtleCrypto даёт ключевые свойства:

  • криптографическая изоляция
  • соответствие современным стандартам (RFC 7515–7519)
  • отсутствие собственной реализации криптографии в JavaScript
  • переносимость между средами выполнения

Это делает jose не криптографической библиотекой в классическом смысле, а высокоуровневым протокол-адаптером над системной криптографией.