Работа с ES256, ES384, ES512

Семейство алгоритмов ES256, ES384 и ES512 основано на схеме ECDSA (Elliptic Curve Digital Signature Algorithm) в сочетании с хэш-функциями SHA-2. Различия между ними определяются используемой длиной хэша и кривой эллиптической криптографии.

  • ES256 — ECDSA с SHA-256 и кривой P-256 (secp256r1)
  • ES384 — ECDSA с SHA-384 и кривой P-384
  • ES512 — ECDSA с SHA-512 и кривой P-521

В библиотеке Jsrsasign данные алгоритмы применяются в контексте цифровых подписей и JSON Web Signature (JWS), а также при работе с криптографическими ключами в формате PEM.


Криптографическая основа ECDSA в Jsrsasign

ECDSA в Jsrsasign реализуется через модуль KJUR.crypto.ECDSA и высокоуровневый интерфейс KJUR.crypto.Signature.

Каждый алгоритм ES256/384/512 использует фиксированную связку:

  • криптографическая кривая (elliptic curve)
  • хэш-функция SHA
  • формат подписи DER (Distinguished Encoding Rules)

Соответствие алгоритмов:

Алгоритм Кривая Хэш Длина ключа
ES256 P-256 SHA-256 256 бит
ES384 P-384 SHA-384 384 бита
ES512 P-521 SHA-512 521 бит

Генерация ключей для ECDSA

Jsrsasign поддерживает генерацию ключевых пар через KEYUTIL.

const kp = KEYUTIL.generateKeypair("EC", "secp256r1");
const privateKey = kp.prvKeyObj;
const publicKey = kp.pubKeyObj;

Для разных алгоритмов используются разные кривые:

// ES256
KEYUTIL.generateKeypair("EC", "secp256r1");

// ES384
KEYUTIL.generateKeypair("EC", "secp384r1");

// ES512
KEYUTIL.generateKeypair("EC", "secp521r1");

Экспорт в PEM формат:

const pemPrv = KEYUTIL.getPEM(privateKey, "PKCS8PRV");
const pemPub = KEYUTIL.getPEM(publicKey);

Подпись данных через KJUR.crypto.Signature

Низкоуровневое создание ECDSA-подписи осуществляется через объект Signature.

ES256

const sig = new KJUR.crypto.Signature({ "alg": "SHA256withECDSA" });
sig.init(privateKey);
sig.updateString("data to sign");
const signatureHex = sig.sign();

ES384

const sig = new KJUR.crypto.Signature({ "alg": "SHA384withECDSA" });
sig.init(privateKey);
sig.updateString("data to sign");
const signatureHex = sig.sign();

ES512

const sig = new KJUR.crypto.Signature({ "alg": "SHA512withECDSA" });
sig.init(privateKey);
sig.updateString("data to sign");
const signatureHex = sig.sign();

Подпись возвращается в формате HEX DER, что является стандартным представлением ECDSA в Jsrsasign.


Проверка подписи

Проверка выполняется тем же объектом Signature, но с публичным ключом.

const sig = new KJUR.crypto.Signature({ "alg": "SHA256withECDSA" });
sig.init(publicKey);
sig.updateString("data to sign");
const isValid = sig.verify(signatureHex);

Аналогично для ES384 и ES512 меняется только алгоритм SHA.


ES256 / ES384 / ES512 в JSON Web Signature (JWS)

Наиболее распространённое применение — цифровые подписи JWT (JSON Web Token). Jsrsasign предоставляет модуль KJUR.jws.JWS.

Формирование JWS (ES256)

const header = { alg: "ES256", typ: "JWT" };
const payload = { sub: "1234567890", name: "Alice", admin: true };

const jwt = KJUR.jws.JWS.sign(
  "ES256",
  JSON.stringify(header),
  JSON.stringify(payload),
  privateKey
);

ES384

const jwt = KJUR.jws.JWS.sign(
  "ES384",
  JSON.stringify(header),
  JSON.stringify(payload),
  privateKey
);

ES512

const jwt = KJUR.jws.JWS.sign(
  "ES512",
  JSON.stringify(header),
  JSON.stringify(payload),
  privateKey
);

Проверка JWS подписи

const result = KJUR.jws.JWS.verify(jwt, publicKey, ["ES256"]);

Для ES384 и ES512 список допустимых алгоритмов расширяется:

KJUR.jws.JWS.verify(jwt, publicKey, ["ES384"]);
KJUR.jws.JWS.verify(jwt, publicKey, ["ES512"]);

Формат подписи в JWS и особенности ECDSA

ECDSA подпись внутри JWS хранится не как DER HEX, а в формате R || S, закодированном через Base64URL.

Jsrsasign автоматически выполняет преобразование:

  • DER (ASN.1) → R/S компоненты
  • R/S → фиксированная бинарная структура
  • бинарные данные → Base64URL

Это важно при интеграции с внешними системами, где формат ECDSA может отличаться.


Base64URL и работа с данными JWS

JWS использует модифицированный Base64:

  • +-
  • /_
  • без = padding

Jsrsasign выполняет это преобразование автоматически при вызове KJUR.jws.JWS.sign.


Выбор кривой и соответствие алгоритму

Несоответствие кривой и алгоритма приводит к ошибкам подписи.

Корректные пары:

  • ES256 → secp256r1 (P-256)
  • ES384 → secp384r1 (P-384)
  • ES512 → secp521r1 (P-521)

Пример неправильной конфигурации:

KEYUTIL.generateKeypair("EC", "secp256r1"); // нельзя использовать с ES512

Работа с PEM и PKCS8 ключами

Jsrsasign поддерживает несколько форматов ключей:

  • PKCS#1 (RSA)
  • PKCS#8 (универсальный формат приватного ключа)
  • SEC1 (для EC ключей)

Импорт PEM:

const prvKey = KEYUTIL.getKey(pemPrivateKey);
const pubKey = KEYUTIL.getKey(pemPublicKey);

Детали реализации ECDSA в Jsrsasign

ECDSA процесс внутри библиотеки включает:

  1. Хэширование сообщения (SHA-256/384/512)
  2. Преобразование хэша в integer
  3. Генерация случайного nonce k (RFC6979 может использоваться детерминированно)
  4. Вычисление точек эллиптической кривой
  5. Формирование пары (r, s)
  6. Кодирование в DER

Типичные ошибки при использовании ES256/384/512

Несовпадение алгоритма в заголовке JWS и подписи

alg: "ES256"
// но используется SHA384withECDSA

Использование неправильной кривой

ES512 + secp256r1 // некорректно

Передача ключа в неверном формате

init("string-key") // ожидается KeyObject

Совместимость с внешними системами

Jsrsasign совместим с:

  • Node.js crypto (частично)
  • OpenSSL ECDSA
  • JWT библиотеками (Auth0, Nimbus JOSE + JWT)

При интеграции важно учитывать:

  • различие DER и RAW формата подписи
  • Base64URL кодирование
  • порядок байтов в R/S

Особенности производительности

  • ES256 быстрее ES384 и ES512
  • ES512 имеет наибольшую криптографическую стойкость, но требует больше вычислений
  • P-256 оптимизирована для большинства веб-сценариев