Основы асимметричного шифрования

Асимметричное шифрование основано на использовании пары ключей: публичного и приватного. Публичный ключ применяется для шифрования данных, приватный — для их расшифровки. Такая модель решает ключевую проблему симметричного шифрования: безопасную передачу секретного ключа.

Принцип работы асимметричной криптографии

В основе лежит математическая связь между двумя ключами:

  • Публичный ключ может свободно распространяться и использоваться любым отправителем
  • Приватный ключ хранится в секрете и используется только владельцем

Данные, зашифрованные публичным ключом, могут быть расшифрованы только соответствующим приватным ключом. Обратная операция невозможна в практическом смысле.

На практике асимметричное шифрование применяется не для больших объёмов данных, а для:

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

Поддержка асимметричных алгоритмов в Web Crypto API

Web Crypto API предоставляет интерфейс crypto.subtle, через который реализуются криптографические операции.

Основные алгоритмы асимметричного шифрования:

  • RSA-OAEP — шифрование и расшифровка
  • RSA-PSS — цифровые подписи
  • ECDSA — подписи на основе эллиптических кривых
  • ECDH — обмен ключами

Генерация пары ключей RSA-OAEP

Создание асимметричной пары ключей выполняется через generateKey.

const keyPair = await crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
  },
  true,
  ["encrypt", "decrypt"]
);

Параметры генерации

  • name — алгоритм (RSA-OAEP)
  • modulusLength — длина ключа в битах (2048 или 4096)
  • publicExponent — стандартное значение 65537
  • hash — хеш-функция для OAEP padding

Результат генерации

Объект содержит:

  • publicKey
  • privateKey

Шифрование данных публичным ключом

Перед шифрованием данные должны быть преобразованы в бинарный формат.

const encoder = new TextEncoder();
const data = encoder.encode("секретное сообщение");

const encrypted = await crypto.subtle.encrypt(
  {
    name: "RSA-OAEP"
  },
  keyPair.publicKey,
  data
);

Особенности операции

  • входные данные ограничены размером ключа
  • результат — ArrayBuffer
  • применяется padding OAEP для защиты от атак

Расшифровка данных приватным ключом

const decrypted = await crypto.subtle.decrypt(
  {
    name: "RSA-OAEP"
  },
  keyPair.privateKey,
  encrypted
);

const decoder = new TextDecoder();
const result = decoder.decode(decrypted);

Форматы ключей: SPKI и PKCS8

Web Crypto API использует стандартизированные форматы экспорта:

  • SPKI — публичные ключи
  • PKCS8 — приватные ключи
  • JWK — JSON Web Key формат

Экспорт публичного ключа

const exportedPublic = await crypto.subtle.exportKey(
  "spki",
  keyPair.publicKey
);

Экспорт приватного ключа

const exportedPrivate = await crypto.subtle.exportKey(
  "pkcs8",
  keyPair.privateKey
);

Импорт ключей

Импорт позволяет восстановить ключи из сохранённого формата.

Импорт публичного ключа

const importedPublic = await crypto.subtle.importKey(
  "spki",
  exportedPublic,
  {
    name: "RSA-OAEP",
    hash: "SHA-256"
  },
  true,
  ["encrypt"]
);

Импорт приватного ключа

const importedPrivate = await crypto.subtle.importKey(
  "pkcs8",
  exportedPrivate,
  {
    name: "RSA-OAEP",
    hash: "SHA-256"
  },
  true,
  ["decrypt"]
);

Ограничения RSA в Web Crypto API

Асимметричное шифрование на основе RSA имеет технические ограничения:

  • максимальный размер данных ограничен длиной ключа
  • 2048-bit RSA позволяет шифровать ~190 байт
  • не подходит для больших сообщений

По этой причине применяется гибридная схема:

  • RSA используется для шифрования симметричного ключа
  • AES — для шифрования данных

Гибридное шифрование

Типовая схема взаимодействия:

  1. Генерация симметричного ключа (AES)
  2. Шифрование данных AES
  3. Шифрование AES-ключа публичным RSA-ключом
  4. Передача обоих элементов
  5. Расшифровка AES-ключа приватным RSA-ключом
  6. Расшифровка данных AES

Цифровая подпись на основе RSA-PSS

Подписи обеспечивают:

  • целостность данных
  • подтверждение отправителя

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

const signKeys = await crypto.subtle.generateKey(
  {
    name: "RSA-PSS",
    modulusLength: 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
  },
  true,
  ["sign", "verify"]
);

Создание подписи

const data = new TextEncoder().encode("сообщение");

const signature = await crypto.subtle.sign(
  {
    name: "RSA-PSS",
    saltLength: 32
  },
  signKeys.privateKey,
  data
);

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

const valid = await crypto.subtle.verify(
  {
    name: "RSA-PSS",
    saltLength: 32
  },
  signKeys.publicKey,
  signature,
  data
);

Эллиптические кривые: ECDH и ECDSA

ECC-криптография обеспечивает:

  • меньшие ключи
  • высокую производительность
  • эквивалентную стойкость RSA при меньшем размере

ECDH (обмен ключами)

Используется для безопасного согласования общего секрета.

const ecdhKeys = await crypto.subtle.generateKey(
  {
    name: "ECDH",
    namedCurve: "P-256"
  },
  true,
  ["deriveKey"]
);

Выведение общего ключа

const derivedKey = await crypto.subtle.deriveKey(
  {
    name: "ECDH",
    public: otherPublicKey
  },
  ecdhKeys.privateKey,
  {
    name: "AES-GCM",
    length: 256
  },
  false,
  ["encrypt", "decrypt"]
);

ECDSA (цифровые подписи)

const ecdsaKeys = await crypto.subtle.generateKey(
  {
    name: "ECDSA",
    namedCurve: "P-256"
  },
  true,
  ["sign", "verify"]
);

Безопасное хранение ключей

Ключи Web Crypto API могут быть:

  • неэкспортируемыми (extractable: false)
  • экспортируемыми (extractable: true)

Неэкспортируемые ключи повышают безопасность, так как:

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

Формат JWK

JSON Web Key позволяет хранить ключи в JSON-структуре.

Экспорт в JWK

const jwkKey = await crypto.subtle.exportKey(
  "jwk",
  keyPair.publicKey
);

Пример структуры:

{
  "kty": "RSA",
  "e": "AQAB",
  "n": "...",
  "alg": "RSA-OAEP-256",
  "ext": true
}

Особенности работы Web Crypto API

  • операции асинхронные и возвращают Promise
  • доступ только через безопасный контекст HTTPS
  • операции выполняются внутри браузерного криптографического ядра
  • прямой доступ к внутренним ключам отсутствует

Типовые сценарии использования асимметричного шифрования

  • защищённый обмен ключами между клиентом и сервером
  • TLS-подобные механизмы на уровне приложения
  • электронные подписи документов
  • аутентификация без передачи пароля
  • распределённые системы идентификации