JWK для RSA: n, e, d, p, q

JSON Web Key (JWK) представляет собой стандартизированное JSON-представление криптографических ключей. Для RSA-ключей JWK описывает математическую структуру алгоритма RSA через набор обязательных и дополнительных параметров. В библиотеке Jsrsasign работа с JWK тесно связана с генерацией, импортом, экспортом и использованием ключей для подписи и проверки JWT, а также для низкоуровневых криптографических операций.

RSA-ключ в формате JWK может содержать как открытые, так и закрытые компоненты. Открытая часть используется для проверки подписи и шифрования, закрытая — для создания подписи и расшифрования.


Структура RSA JWK

RSA JWK всегда содержит параметр kty, который определяет тип ключа:

  • kty: "RSA" — ключ RSA

Далее идут базовые параметры:

  • n — модуль RSA (modulus)
  • e — открытая экспонента (public exponent)

Для приватного ключа добавляются дополнительные поля:

  • d — приватная экспонента (private exponent)
  • p — первый простой множитель
  • q — второй простой множитель
  • dp — d mod (p − 1)
  • dq — d mod (q − 1)
  • qi — q⁻¹ mod p

Математический смысл параметров RSA

RSA основан на разложении большого числа на простые множители.

n — модуль

n = p q

Параметр n является произведением двух больших простых чисел p и q. Он используется как часть открытого и закрытого ключа.


e — открытая экспонента

e

e — число, которое используется для шифрования и проверки подписи. Чаще всего встречается значение 65537, так как оно обеспечивает баланс между безопасностью и производительностью.


d — закрытая экспонента

d e^{-1} }

d — обратное значение к e по модулю функции Эйлера. Именно оно используется для создания цифровой подписи и расшифровки данных.


p и q — простые множители

n = p q

Пара p и q — секретные простые числа, на которых строится вся безопасность RSA. Их утечка полностью компрометирует ключ.


dp, dq и qi

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

  • dp = d mod (p − 1)
  • dq = d mod (q − 1)
  • qi = q⁻¹ mod p

Они позволяют значительно ускорить операции подписи и расшифровки.


Формат JWK RSA

Пример структуры приватного RSA JWK:

{
  "kty": "RSA",
  "n": "base64url-modulus",
  "e": "AQAB",
  "d": "base64url-private-exponent",
  "p": "base64url-prime1",
  "q": "base64url-prime2",
  "dp": "base64url-exponent1",
  "dq": "base64url-exponent2",
  "qi": "base64url-coefficient",
  "alg": "RS256",
  "use": "sig",
  "kid": "key-id"
}

Открытый ключ содержит только:

{
  "kty": "RSA",
  "n": "base64url-modulus",
  "e": "AQAB"
}

Работа с RSA JWK в Jsrsasign

Jsrsasign предоставляет удобные средства для конвертации JWK в внутренние представления ключей и обратно.

Импорт JWK в KEYUTIL

const keyObj = KEYUTIL.getKey({
  kty: "RSA",
  n: "....",
  e: "AQAB",
  d: "....",
  p: "....",
  q: "....",
  dp: "....",
  dq: "....",
  qi: "...."
});

После этого keyObj становится объектом, который можно использовать для подписания или проверки JWT.


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

Jsrsasign позволяет генерировать RSA ключи и получать их в формате JWK:

const kp = KEYUTIL.generateKeypair("RSA", 2048);

const pubJwk = KEYUTIL.getJWKFromKey(kp.pubKey);
const privJwk = KEYUTIL.getJWKFromKey(kp.prvKey);

Подпись данных с использованием RSA JWK

После получения приватного ключа:

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

const sHeader = JSON.stringify(header);
const sPayload = JSON.stringify(payload);

const jwt = KJUR.jws.JWS.sign(
  "RS256",
  sHeader,
  sPayload,
  privKey
);

Где privKey — ключ, полученный через KEYUTIL.getKey() из JWK.


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

const isValid = KJUR.jws.JWS.verifyJWT(jwt, pubKey, {
  alg: ["RS256"]
});

Публичный ключ содержит только n и e, что делает его безопасным для распространения.


Преобразование JWK ↔︎ PEM

Jsrsasign поддерживает преобразование между форматами:

JWK → PEM

const key = KEYUTIL.getKey(jwk);
const pem = KEYUTIL.getPEM(key);

PEM → JWK

const key = KEYUTIL.getKey(pem);
const jwk = KEYUTIL.getJWKFromKey(key);

Особенности хранения p и q

Параметры p и q никогда не включаются в публичные ключи. Их утечка приводит к возможности факторизации n и восстановлению d.

В реальных системах:

  • p и q хранятся только в защищённом хранилище
  • экспортируются только при необходимости резервного копирования
  • часто отсутствуют даже в некоторых HSM-реализациях на уровне API

Внутренние вычисления RSA в Jsrsasign

При использовании приватного ключа Jsrsasign может использовать CRT-оптимизацию:

m^d n

Заменяется на:

m_1 = m^{dp} p,m_2 = m^{dq} q

Далее результат объединяется через:

h = (q^{-1}(m_1 - m_2)) p

и

m = m_2 + hq

Эта оптимизация критична для производительности при больших ключах (2048–4096 бит).


Использование только n и e

Публичный RSA JWK минимально состоит из:

  • n — модуль
  • e — экспонента

Этого достаточно для:

  • проверки подписи JWT
  • шифрования данных
  • построения публичного ключа в любом криптографическом провайдере

Практическая структура данных Jsrsasign

Внутри Jsrsasign ключи представлены не как чистый JWK, а как объект с методами:

  • signString()
  • verifyString()
  • encrypt()
  • decrypt()

JWK выступает как формат сериализации для передачи между системами.


Ошибки при работе с JWK RSA

Наиболее частые проблемы:

  • неверный base64url-формат n или e
  • отсутствие обязательного поля kty
  • несовпадение длины ключа и параметров CRT
  • попытка использовать приватные поля с публичным ключом
  • неправильная кодировка чисел (BigInt vs string)

Безопасная работа с p и q

Критические правила при обработке:

  • не логировать JWK с p и q
  • не передавать приватный JWK в клиентский код
  • минимизировать время хранения полного ключа в памяти
  • использовать только при генерации или подписи

Связь JWK и JWT в Jsrsasign

RSA JWK чаще всего используется в контексте JWT:

  • n и e — проверка подписи токена
  • d, p, q — создание подписи токена

Алгоритмы:

  • RS256 (RSA + SHA-256)
  • RS384
  • RS512