Flattened JWE представляет собой компактное JSON-представление зашифрованного сообщения, в котором результат шифрования хранится в виде единого объекта с явным разделением полей. В отличие от General JWE Serialization, flattened-формат не использует массив recipients и предназначен для сценариев с одним получателем.
Структура включает ключевые компоненты:
Flattened формат применяется, когда требуется минимизировать структуру без потери криптографических гарантий.
В библиотеке jose реализация Flattened JWE представлена классом
FlattenedEncrypt. Он инкапсулирует процесс формирования
JWE, начиная от установки заголовков и заканчивая финальной
сериализацией.
Основная идея заключается в поэтапном построении объекта:
Типичный сценарий начинается с создания экземпляра
FlattenedEncrypt, которому передаётся исходный
plaintext.
import { FlattenedEncrypt } from 'jose'
const encoder = new TextEncoder()
const jwe = await new FlattenedEncrypt(
encoder.encode('секретные данные')
)
На этом этапе данные ещё не зашифрованы, объект лишь подготавливает структуру.
Protected header определяет алгоритмы и параметры шифрования. Он является критически важной частью JWE, так как участвует в вычислении authentication tag.
const jwe = await new FlattenedEncrypt(
encoder.encode('секретные данные')
)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
alg — алгоритм шифрования ключа (Key Management
Algorithm)enc — алгоритм симметричного шифрования
содержимогоКомбинация этих параметров определяет криптографическую стойкость всей конструкции.
FlattenedEncrypt требует публичный ключ получателя для шифрования CEK
(Content Encryption Key). В случае RSA используется криптографический
ключ формата KeyLike.
import { importJWK } from 'jose'
const publicKey = await importJWK(jwkPublicKey, 'RSA-OAEP-256')
Далее ключ подключается через метод encryptKey:
const jwe = await new FlattenedEncrypt(
encoder.encode('секретные данные')
)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
.encryptKey(publicKey)
Финальная стадия выполняется методом encrypt(), который
принимает дополнительные параметры, включая IV и AAD (если
требуется).
const result = await new FlattenedEncrypt(
encoder.encode('секретные данные')
)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
.encryptKey(publicKey)
.encrypt()
Результатом является объект Flattened JWE:
{
"protected": "base64url(header)",
"encrypted_key": "base64url(...)",
"iv": "base64url(...)",
"ciphertext": "base64url(...)",
"tag": "base64url(...)"
}
Дополнительные данные аутентификации (Additional Authenticated Data) позволяют привязать внешнюю информацию к криптограмме без её шифрования.
const jwe = await new FlattenedEncrypt(
encoder.encode('секретные данные')
)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM',
typ: 'JWE'
})
.setAdditionalAuthenticatedData(
encoder.encode('контекст сообщения')
)
.encryptKey(publicKey)
.encrypt()
AAD участвует в вычислении тега аутентификации, но не входит в ciphertext.
Flattened JWE позволяет разделять защищённые и незащищённые метаданные. Unprotected header не включается в вычисление подписи.
const jwe = await new FlattenedEncrypt(
encoder.encode('секретные данные')
)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
.setUnprotectedHeader({
kid: 'key-1'
})
.encryptKey(publicKey)
.encrypt()
Такой подход используется для хранения идентификаторов ключей и вспомогательной информации.
Разделение ответственности между alg и enc
является ключевым принципом JWE:
alg управляет доставкой симметричного ключаenc определяет алгоритм шифрования данныхПример типичных комбинаций:
RSA-OAEP-256 + A256GCMECDH-ES + A256GCMA256KW + A128CBC-HS256Каждая комбинация определяет как безопасность, так и производительность операции.
Реализация FlattenedEncrypt в jose ориентирована на строгую совместимость со стандартом JWE RFC 7516. Основные особенности:
Flattened формат чаще используется в API-сценариях, где каждый JWE связан с одним получателем и требуется минимальный размер JSON-структуры.
Если алгоритм не соответствует типу ключа, шифрование завершится
ошибкой на этапе encryptKey.
Параметр enc обязателен, так как определяет симметричное
шифрование.
RSA-алгоритмы требуют публичного ключа, ECIES — соответствующей пары ключей.
FlattenedEncrypt работает с бинарными данными через
Uint8Array. Это позволяет избежать лишних преобразований
строк:
const data = new TextEncoder().encode('payload')
Результаты также возвращаются в виде base64url-строк, что обеспечивает совместимость с JSON-сериализацией.
Процесс можно представить как последовательность преобразований:
После выполнения encrypt() библиотека возвращает обычный
JavaScript-объект. Он может быть напрямую сериализован:
JSON.stringify(jwe)
При этом порядок полей не влияет на криптографическую корректность, так как проверка осуществляется через protected header и authentication tag.