Эллиптические кривые занимают центральное место в современных схемах цифровой подписи и распределения ключей. В контексте JOSE (JSON Object Signing and Encryption) они используются в двух основных направлениях: цифровые подписи (JWS) и согласование ключей (JWE через ECDH-ES). Библиотека jose в JavaScript предоставляет унифицированный интерфейс для работы с этими механизмами, скрывая сложность низкоуровневой криптографии и обеспечивая корректную реализацию стандартов.
Эллиптическая кривая в криптографии задаётся уравнением вида:
y^2 = x^3 + ax + b
где коэффициенты (a) и (b) выбираются так, чтобы кривая не содержала особенностей (дискриминант не равен нулю). Множество точек на такой кривой вместе с точкой на бесконечности образуют абелеву группу.
Ключевая операция — скалярное умножение точки:
Q = d G
где:
Сложность обратной задачи (дискретный логарифм на эллиптической кривой) обеспечивает криптографическую стойкость.
В спецификациях JOSE поддерживаются стандартные кривые, определённые NIST:
Каждая кривая связана с конкретными алгоритмами подписи:
ECDSA (Elliptic Curve Digital Signature Algorithm) применяется в JWS (JSON Web Signature). Библиотека jose реализует формирование подписи как детерминированный процесс над хэшем сообщения.
Схема подписи:
Вычисление хэша сообщения:
Генерация случайного числа (k)
Вычисление точек на кривой
Формирование пары значений (r, s)
Подпись представляется как конкатенация двух чисел фиксированной длины.
В JOSE подпись применяется к структуре:
BASE64URL(header) + "." + BASE64URL(payload)
и результат кодируется в base64url.
import { SignJWT, importPKCS8 } from 'jose'
const privateKey = await importPKCS8(pemPrivateKey, 'ES256')
const jwt = await new SignJWT({ sub: '1234567890' })
.setProtectedHeader({ alg: 'ES256' })
.setIssuedAt()
.setExpirationTime('2h')
.sign(privateKey)
При проверке:
import { jwtVerify, importSPKI } from 'jose'
const publicKey = await importSPKI(pemPublicKey, 'ES256')
const { payload } = await jwtVerify(token, publicKey)
Ключи на эллиптических кривых в JOSE кодируются в формате JWK (JSON Web Key).
Пример EC ключа:
{
"kty": "EC",
"crv": "P-256",
"x": "base64url_x_coordinate",
"y": "base64url_y_coordinate",
"d": "base64url_private_scalar"
}
Поля:
kty — тип ключа (EC)crv — криваяx, y — координаты публичной точкиd — приватный ключ (только для приватных ключей)Публичный ключ содержит только x и y.
ECDH (Elliptic Curve Diffie-Hellman) используется в JWE (JSON Web Encryption) для безопасного обмена симметричным ключом.
Базовая формула общего секрета:
S = d_A Q_B = d_B Q_A
где:
В JOSE используется вариант ECDH-ES, где из общего секрета выводится ключ шифрования через KDF (Key Derivation Function).
Пример генерации зашифрованного JWE:
import { generateKeyPair, EncryptJWT } from 'jose'
const { publicKey, privateKey } = await generateKeyPair('ECDH-ES', {
crv: 'P-256'
})
const jwe = await new EncryptJWT({ data: 'secret' })
.setProtectedHeader({ alg: 'ECDH-ES', enc: 'A256GCM' })
.setIssuedAt()
.setExpirationTime('2h')
.encrypt(publicKey)
Расшифрование:
import { jwtDecrypt } from 'jose'
const { payload } = await jwtDecrypt(jwe, privateKey)
После получения общего секрета применяется функция вывода ключа. В JOSE используется Concat KDF.
Упрощённая модель:
K = KDF(S, , , )
где:
alg — алгоритм шифрованияapu, apv — дополнительные параметры
участниковБиблиотека jose строго следует спецификации RFC 7518:
ECDSA-реализация использует deterministic nonce (RFC 6979), что
устраняет зависимость от случайности при генерации k.
Внутренне ECDSA подпись состоит из двух чисел:
В JOSE они кодируются как DER или raw формат (в зависимости от реализации), но в JWT/JWS используется base64url encoding финального бинарного представления.
ECDSA обладает рядом характеристик, определяющих его популярность в JOSE:
RSA в JWS требует значительно больших ключей (2048+ бит), тогда как EC обеспечивает эквивалентную стойкость при 256 битах.
Безопасность EC-схем в JOSE зависит от:
Слабая реализация любого из этих компонентов приводит к полной компрометации системы, несмотря на математическую стойкость алгоритма.
EC-алгоритмы в JOSE применяются в:
Использование jose в JavaScript-экосистеме позволяет унифицировать работу с этими механизмами без прямого обращения к низкоуровневым криптобиблиотекам.